关于vue
生命周期,希望你有所收获
前言
vue
作为目前主流的三大前端框架之一,现在在市场上也很火,笔者从事前端开发以来,接触的项目大多数都是用vue
开发的,相较于其他两个框架呢,vue
也是简单易上手,虽说简单易上手,但也会踩一些坑,也会遇到不理解的问题。vue
官网上写的很清楚,也很详细,作为官网,语言自然是很官方,用了很多专业术语,很多时候不是一下就能看明白的。做技术的要懂得分享,用很直白的话去解释一个技术问题,后来的人也会更容易懂,避免踩一些不必要的坑。
如果你即将用或者准备用vue
做开发,最好是现在就搞懂搞明白它,或许你将来在开发当中遇到的一些问题就是它引起的,现在拿下它,避免一些不必要的坑。
vue
生命周期到底是什么
每个vue
实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue
的生命周期。你可以理解为一个工艺品的一生,这个工艺品生产出来,被人所使用,再到用完被销毁的过程,这一系列过程下来完成了这个工艺品的一生,这个过程就是生命周期。vue
官网有一张图很好的诠释了整个vue
的生命周期
vue
的生命周期总共分八个步骤,这八个步骤也被称之为八个钩子函数,分别是:
beforeCreate
(创建前)
created
(创建后)
beforeMount
(载入前)
mounted
(载入后)
beforeUpdate
(更新前)
updated
(更新后)
beforeDestroy
(销毁前)
destroyed
(销毁后)
一段代码
首先,我们运行一段代码,看看这段代码会发生什么,然后再分析这段代码输出的结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue生命周期</title>
</head>
<body>
<div id="app">
<p>{{message}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data() {
return {
message: 'vue生命周期'
}
},
beforeCreate() {
console.group('-----beforeCreate-----');
console.log("%c%s", "color:green", "el :" + this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
created() {
console.group('-----created-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
beforeMount() {
console.group('-----beforeMount-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
mounted() {
console.group('-----mounted-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
beforeUpdate() {
console.group('-----beforeUpdate-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
updated() {
console.group('-----updated-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
befogreenestroy() {
console.group('-----befogreenestroy-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
},
destroyed() {
console.group('-----destroyed-----');
console.log("%c%s", "color:green", "el: :" + this.$el);
console.log(this.$el);
console.log("%c%s", "color:green", "data :" + this.$data);
console.log("%c%s", "color:green", "message :" + this.message);
}
})
</script>
</body>
</html>
一个结果
结果分析
由上图的结果我们可以看到,vue
实例在创建过程中总共调用了四个钩子函数。
####beforeCreate
和created
在beforeCreate
这个生命周期期间,初始化事件,并对数据进行观测,刚开始所有的数据,属性包括dom
节点都不可用,都为undefined
。可以看到在created
的时候此时数据已经和data
属性进行绑定,并且能打印出具体的值。在created
到beforeMount
这个阶段,首先会判断对象是否有el选项,如果有的话就继续向下编译,如果没有el选项,就会停止编译,也就意味着会停止生命周期,直到在该vue实例上调用vm.$mount(el)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue生命周期</title>
</head>
<body>
<div id="app">
<p>{{message + '这是外部html中的'}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
template: "<p>{{message + '这是在template中的'}}</p>",
data() {
return {
message: 'vue生命周期'
}
}
})
</script>
</body>
</html>
template参数选项的有无对生命周期的影响,如果Vue实例对象中有template参数选项,则将其作为模板编译成render函数;如果没有template选项,则将外部的HTML作为模板编译;根据上述代码执行的结果,可以发现template中的模板优先级要高于外部HTML的优先级。这也是为什么el的判断要在template之前了,因为vue需要通过el找到对应的外部template。另外vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,并且直接可以嵌入JSX。
render函数选项的优先级是高于template选项的。
beforeMount
和mounted
beforeMount
这个阶段给vue实例对象添加$el成员,并且替换掉了DOM元素。在这之前控制台打印的还是undefined。
mounted
这个阶段页面内容已经发生了变化,数据已经页面上渲染完毕。
beforeUpdate
和updated
当vue发现data中的数据发生了改变,会触发对应组件的重新渲染,会先后调用者两个钩子函数。如果在mounted
这个阶段改变数据值,是不会触发beforeUpdate
,beforeUpdate
是针对视图层的,视图层的数据发生改变才会触发这个钩子函数。
如果视图层数据被改变后,会触发beforeUpdate
,如果在beforeUpdate
里再一次改变数据,此时会再一次触发beforeUpdate
吗?答案是不会的。原因是:mounted
改变了数据,视图层的数据发生变化,此时触发beforeUpdate
,尽管beforeUpdate
再次改变了数据,但此时mounted
改变过后的数据还没有更新到视图层,因此在beforeUpdate
里再次变化数据的是没有更新到视图层的数据,当然不会再次触发beforeUpdate
。
那假如在updated
里改变数据呢?此时的由mounted
改变的数据已经跟新至视图层,此时在updated
改变数据就会触发beforeUpdate
。
####beforeDestroy
和destroyed
beforeDestroy
钩子函数在vue实例销毁之前调用,在这一步,实例仍然完全可用。
destroyed
钩子函数在vue实例销毁后调用。调用后,vue实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。