Vue的生命周期详解
一. 官方的生命周期图与对应解释
二.实例生命周期钩子详解
我用两个组件切换来展示组件各个生命周期钩子的调用时间。
并在两个组件内设置修改data值的函数,以便构成更新后的钩子调用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-link to="/bar">bar</router-link><br/><br/>
<router-link to="/foo">foo</router-link><br/><br/>
<router-view/>
</div>
<script type="text/javascript">
var bar = {
template: '<div><button @click="changeBar">修改bar的data</button><br/><br/><p>bar组件---{{message}}</p></div>',
data() {
return {
message:'I am bar '
}
},
methods: {
changeBar() {
this.message = 'change bar !!!'
}
},
beforeCreate: function () {
console.group('bar组件的 beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)
},
created: function () {
console.group('bar组件的 created 创建完毕状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('bar组件的 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('bar组件的 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('bar组件的 beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('bar组件的 updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('bar组件的 beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + (this.$el));
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('bar组件的 destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + (this.$el));
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
}
var foo = {
template: '<div><button @click="changeFoo">修改Foo的data</button><br/><br/><p>foo组件---{{message}}</p></div>',
data() {
return {
message:'I am foo '
}
},
methods: {
changeFoo() {
this.message = 'change foo !!!'
}
},
beforeCreate: function () {
console.group('foo组件的 beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)
},
created: function () {
console.group('foo组件的 created 创建完毕状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('foo组件的 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('foo组件的 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('foo组件的 beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('foo组件的 updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('foo组件的 beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('foo组件的 destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el.innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
}
const router = new VueRouter({
routes: [
{
path:'/foo',
component:foo
},
{
path:'/bar',
component:bar
}
],
})
const vm = new Vue({
el: '#app',
router
})
</script>
</body>
</html>
效果如下,此时还没有进入子组件,所以还没有调用生命周期钩子,因为我没有在父组件上使用生命周期钩子,所以控制台还是空
1.beforeCreate和created
由上图可知,beforeCreate是在组件实例刚刚创建时调用的,这时组件内的属性全都没有计算,
如data,还有DOM也没有生成,所以$el也不存在($el就是对应组件的DOM结构,如<div></div>
之类的)
created则是在组件实例创建后调用的,此时组件内的属性如data就已经被初始化了,
data属性内的值也被初始化了,但是由于DOM结构还没有渲染,使用$el还是不存在
2.beforeMount和mounted
beforeMount:
是在组件挂载之前调用的,什么是挂载呢?其实就是组件DOM结构出现在页面上,
beforeMount执行的时候DOM结构还没出现在页面上,所以不能获取this.$el
mounted:
执行的时候,此时页面就加载出来了,DOM结构出现在了页面上,this.$el也就
可以拿到DOM结构了
3.beforeUpdate 和 updated
beforeUpdate :
是在组件更新之前调用的,此时的状态还是更新前的状态,比如data里面的值还是之前的值
updated:
是在组件更新之后调用的,此时状态已经是更新后的状态了
我用this.$el.innerHTML来展示内部的html代码,为什么不和前面一样直接使用this.$el
拿到DOM结构再来看有没有什么不同呢?因为this.$el 是一个对象,相当于一个指针,因此
当你使用 console.log 输出之后,其内容并没有真正显示,而当你点开下面的箭头展开具体
内容时,显示的是该指针指向对象的当前内容,所以无法判断更新前后的变化,而使用
this.$el.innerHTML可以直接获取DOM结构的html代码,便于我们观察更新前后的变化
4.beforeDestroy 和destroyed
beforeDestroy :
是在组件被销毁前调用的,什么是销毁呢?简单来说就是组件切换时,上一个组件就被销毁了
destroyed:
是组件销毁后调用的
可以看到,组件销毁是在另一个之前挂载到页面后和挂载到页面前中间,即 beforeMount和mounted 钩子调用之间调用的
总结:
一般情况我们获取数据而且是不涉及DOM操作的请求我们放在created()里面,因为此时组件内部的属性已经存在,可以进行取值与赋值,但是如果涉及DOM操作就要放在mounted()里面了,不然获取不到DOM元素,其他钩子用的相对较少,但是我相信学到后面会慢慢清除他们的用处,到时肯定有所收益
参考文献:
https://segmentfault.com/a/1190000008010666?utm_source=tag-newest
通过上面那位老哥对生命周期钩子的解释再进行的分析