Vue2.x的生命周期详解

使用Vue开发已经有一段时间了。但发现自己对vue的理解还是不深刻。于是想着从观看Vue文档开始。在阅读文档之前,觉得需要先了解整个Vue的生命周期,清楚的认识到Vue在每个阶段的钩子函数没这样才能更好的让我们去使用Vue

我们先来看一张图,上面解释每个步骤是做什么的。可以只看这一张图就可以明白Vue实例的整个流程。

每个Vue实例在被创建之前都要经历过一系列的初始化过程,这个过程就是Vue的生命周期。浅显的来说,生命周期的钩子函数就是回调函数,在不同的阶段有不同的回调函数供用户处理自定义的事件。也可以说生命周期是一套流程,而这套流程里面的方法会有先后顺序的执行(调用就执行,不调用就不执行)。

生命周期钩子

从上面的图中会看到生个vue的生命周期钩子:

  • beforeCreate

  • created

  • beforeMount

  • mounted

  • beforeUpdate

  • updated

  • beforeDestroy

  • destroyed

当然除了实例的生命周期,还有其他的:

  • activated: keep-alive 缓存组件激活时使用
  • deactivated: keep-alice 缓存组件停用时使用
  • errorCaptured: 捕获一个来自子孙组件的错误时调用

beforeCreate 之前

beforeCreate生命周期之前。首先是使用new Vue来开始创建一个Vue实例、接下来会初始化这个实例的生命周期事件。如下图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app"> <h1>{{message}}</h1></div></body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "舒丽琦"
},
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
},
beforeCreate () {
console.log("------beforeCreate------");
console.log("el:", this.$el);
console.log("data:", this.$data);
console.log("methods:", this.getMessage);
},
})
</script>
</html>

打印结果:

1
2
3
4
------beforeCreate------
el: undefined
data: undefined
methods: undefined

beforeCreate 和 created 之间

在这个生命周期之前,会初始化当前实例上的datamethods。说明created的时候数据已经绑定,是可以访问到了。在这里可以做ajax请求了。

注意:这里还没有 el 选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app"> <h1>{{message}}</h1></div></body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "舒丽琦"
},
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
},
beforeCreate () {
console.log("------beforeCreate------");
console.log("el:", this.$el);
console.log("data:", this.$data);
console.log("methods:", this.getMessage);
},
created () {
console.log("------created------");
console.log("el:", this.$el);
console.log("data:", this.$data.message);
console.log("methods:", this.getMessage());
}
})
</script>
</html>

结果打印:

1
2
3
4
5
6
7
8
------beforeCreate------
el: undefined
data: undefined
methods: undefined
------created------
el: undefined
data: 舒丽琦
methods: 方法返回:舒丽琦

可以看出,created可以获取datamethods

created 和 beforeMount 之间的生命周期

这阶段里面首先会判断是否有el选项。如果有的话,那么继续往下编译,如果没有el选项。则停止编辑。也就意味停止了生命周期。直到该Vue实例上调用了Vm.$mount(el)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app"> <h1>{{message}}</h1></div></body>
<script>
var vm = new Vue({
// el: '#app', // 被注释掉了
data: {
message: "舒丽琦"
},
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
},
created() {
console.log("------created--------")
},
beforeMount() {
console.log("------beforeMount------");
console.log("el:", this.$el);
console.log("data:", this.$data.message)
console.log("methods:", this.getMessage());
},
})
</script>
</html>

结果打印:

1
------created--------

手动调用实例的Vm。$mount(#app):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app"> <h1>{{message}}</h1></div></body>
<script>
var vm = new Vue({
// el: '#app', // 被注释掉了
data: {
message: "舒丽琦"
},
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
},
created() {
console.log("------created--------")
},
beforeMount() {
console.log("------beforeMount------");
console.log("el:", this.$el);
console.log("data:", this.$data.message)
console.log("methods:", this.getMessage());
},
})
vm.$mount("#app"); // 手动调用了 Vm.$mount(el)
</script>
</html>

结果打印:

然后会判断是否有template。有没有template对生命周期没有影响。

  • 如果有template则直接作为模板编译成render函数;
  • 如果没有template则直接将外部的html作为模板编译;

注意:template模板的优先级要高于外部html的优先级。

如下的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<span>这是外部的html模板:{{message}}</span>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "舒丽琦"
},
template: "<span>这是内部的模板:{{message}}</span>",
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
}
})
</script>
</html>

打开之后,我们看到的页面文案是:”这是内部的模板:舒丽琦”

如果我们把template 删除掉那么就会显示:”这是外部的html模板:舒丽琦”6

beforeMount 和 mounted之前的生命周期

这期间Vue实例对象添加$el。把内存中渲染好的html 替换到页面上。覆盖$el指定的页面。因为在这之前的beforeCreate生命周期打印的el还是undefined

mounted生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<span>这是外部的html模板:{{message}}</span>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "舒丽琦"
},
template: "<span>这是内部的模板:{{message}}</span>",
methods: {
getMessage() {
return `方法返回:${this.message}`;
}
},
mounted() {
console.log("--------mounted--------");
console.log("el:", this.$el);
}
})
</script>
</html>

打印结果为:

1
2
--------mounted--------
el: <span>​这是内部的模板:舒丽琦​</span>​

在这之前的span标签的名字是 占位的。这是JavaScript中的虚拟DOM形式存在的。在mounted之后就可以看到了内容发生了变化。

beforeUpdate 和 updated 之间的生命周期

从图中可以看出来, 当data的数据发生了变化,先会触发beforeUpdate钩子。注意这时候页面的视图还没更新。然后才重新渲染组件。最后调用updated。调用完之后。视图和data都是最新的。

我们看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue2.x生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<span>这是外部的html模板:{{message}}</span>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "老的数据"
},
beforeUpdate() {
console.log("--------beforeUpdate--------");
console.log("el:", this.$el);
},
updated() {
console.log("--------updated--------");
console.log("el:", this.$el);
}
})
vm.message = "新的数据";
</script>
</html>

打印结果:

当数据data有改变的( vm.message = “新的数据”)。就会分别触发beforeUpdateupdated

beforeDestroy 和 destroyed 之间的生命周期

beforeDestroy 生命周期是在实例被销毁之前调用。在这一步,实例仍然是可用的。

destroyed生命周期是在实例销毁之后调用。调用后。Vue实例所指的所有东西都会被解除绑定。所有的事件也会被移除。所有的子实例也会被销毁。

activated

keep-alive 缓存组件激活的时候使用

deactivated

keep-alive 缓存组件停用时使用

errorCaptured

捕获子孙组件的错误时调用

数据请求在created和mouted的区别

created是在组件实例一旦创建完成的时候立刻调用,这时候页面dom节点并未生成,mounted是在页面dom节点渲染完毕之后就立刻执行的,触发时机上created是比mounted要更早的:两者相同点:都能拿到实例对象的属性和方法;讨论这个问题本质就是触发的时机,放在mounted请求有可能导致页面闪动(页面dom结构已经生成),但如果在页面加载前完成则不会出现此情况建议:放在create生命周期当中

文章作者: 舒小琦
文章链接: https://shuliqi.github.io/2018/04/17/Vue2-x的生命周期详解/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 舒小琦的Blog