vue生命周期——超详细
每个 Vue 实例创建时,都会经历一系列的初始化过程,同时也会调用相应的生命周期钩子。生命周期关于 Vue 生命周期,先放一张官方文档的图在这个图中我们可以清楚地看到 Vue 的整个生命周期和它所提供的钩子函数。钩子函数beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatebeforeDestroydestroye...
每个 Vue 实例创建时,都会经历一系列的初始化过程,同时也会调用相应的生命周期钩子。
生命周期
关于 Vue 生命周期,先放一张官方文档的图
在这个图中我们可以清楚地看到 Vue 的整个生命周期和它所提供的钩子函数。
钩子函数
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- update
- beforeDestroy
- destroyed
首先先运行一下下列代码,看看会发生什么,然后再慢慢分析。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue生命周期</title>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Vue生命周期'
},
beforeCreate: function () {
console.group('-----beforeCreate-----');
console.log("%c%s", "color:red", "el :" + this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
created: function () {
console.group('-----created-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
beforeMount: function () {
console.group('-----beforeMount-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
mounted: function () {
console.group('-----mounted-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
beforeUpdate: function () {
console.group('-----beforeUpdate-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
updated: function () {
console.group('-----updated-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
beforeDestroy: function () {
console.group('-----beforeDestroy-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
},
destroyed: function () {
console.group('-----destroyed-----');
console.log("%c%s", "color:red", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data :" + this.$data);
console.log("%c%s", "color:red", "message :" + this.message);
}
});
</script>
</body>
</html>
代码运行结果如下:
由此我们可以看到,在 Vue 创建实例的过程中,调用了几个生命周期钩子。
1. beforeCreate 和 created 钩子函数之间的生命周期。
在这个生命周期之间,进行初始化事件,进行数据的观测,可以看到在 created 的时候数据已经和 data 属性进行绑定。但此时尚未挂载,el 还不可用。
2. created 和 beforeMount 之间的生命周期
如图,在这一阶段,首先会判断对象是否有 el 选项(option)。如果有的话就继续向下编译;如果没有则停止编译,也就意味着停止了生命周期,直到在该 Vue 实例上调用 vm.$mount(el)。
做个试验来看一下,在上面的示例代码中将 el 属性注释掉,则运行结果:
可以看到,当没有 el 选项时,代码运行到 created 的时候就停止了。
从图中可以看出,当判断有 el 选项时,代码会继续向下执行,接下来会判断是否有 template 选项。同样从图中可以看出:
- 如果 Vue 实例对象中有 template 选项,则将其作为模板编译成 render 函数。
- 如果没有 template 选项,则将外部 HTML(outerHTML)作为模板编译。
- 由此可以看出,template 中的模板优先级要高于 outerHTML 的优先级。
我们也可以做个实验来验证一下。运行下面的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue生命周期学习</title>
</head>
<body>
<div id="app">
<!--html中修改的-->
<h1>{{message + '---这是在outer HTML中的'}}</h1>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script>
var vm = new Vue({
el: '#app',
template: "<h1>{{message +'---这是在template中的'}}</h1>", //在vue配置项中修改的
data: {
message: 'Vue的生命周期'
}
});
</script>
</html>
执行后的结果为:
如果将 Vue 对象中的 template 属性注释掉则结果为:
结果跟我们从图中得出的结论的是一样的。
在 vue 对象中还有一个 render 函数,它是以 createElement 作为参数,然后做渲染操作。
new Vue({
el: "#app",
render: function (createElement) {
return createElement('h1', 'This is createElement.');
}
})
页面中渲染的是:
所以综合排名优先级:
render 函数选项 > template 选项 > outerHTML
3. beforeMount 和 mounted 之间的生命周期。
可以看到此时是给 vue 实例对象添加 $el 成员,并且替换掉挂载的 DOM 元素。在之前的结果图中可以看到 beforeMount 之前 el 还是 undefined。
4. mounted
注意看之前代码生成的结果图:
从图中我们可以清楚地看到,在 mounted 之前,h1 中还是通过 {{message}} 来占位的,因为此时还没有被挂到页面上,还是 JavaScript 中的虚拟 DOM 形式存在的。在 mounted 之后才发生了变化。
5. beforeUpdate 和 updated 之间的生命周期
从图中我们可以看到,当 vue 中的数据发生改变,会触发对应组件的重新渲染(re-render),先后调用 beforeUpdate 和 updated 钩子函数。
继续做实验,我们在控制台中输入:
vm.message = '触发组件更新'
控制台输出为:
我们可以看到触发了这两个钩子函数。
这里需要注意的一点是,两个函数中的 data 都已经更新为 “触发组件更新”,那区别是什么呢?
注意:
这里的 update 指的是,view 层的 update,而不是 vue 对象中 data 属性的 update。所以,这两个函数都发生在 data 改变之后(很容易理解,因为就是 data 属性的改变才触发了这两个函数),区别是 beforeUpdate 发生在 view 层的改变之前,也就是页面还没有重新渲染,此时页面仍然显示 “Vue的生命周期”(beforeUpdate 也是在页面重新渲染前修改 data 的最后时机);而 updated 是发生在 view 层改变之后,也就是此时的页面已经重新渲染为 “触发组件更新”。
6. beforeDestroy 和 destroyed 之间的生命周期
beforeDestroy 是在实例被销毁之前调用,在这一步,实例仍然完全可以调用。
destroyed 函数在实例被销毁之后调用,此时 vue 实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。
更多推荐
所有评论(0)