1、生命周期概述
什么是生命周期,从Vue
实例创建、运行、到销毁期间,总是伴随着各种各样的事件。而这些事件,被称为生命周期。
每个Vue实例在被创建时都要经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如created
钩子可以用来在一个实例被创建之后执行代码:
<div id="root">
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello'
},
created: function(){
//this指向vm示例
console.log("msg is "+ this.msg);
}
});
</script>
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如:mounted
、updated
和 destroyed
。生命周期钩子的 this
上下文指向调用它的 Vue
实例。
不要在选项属性或回调上使用箭头函数,比如:
created:()=> console.log(this.a)
或vm.$watch('a',newvalue => this.myMethod())
。因为箭头函数并没有this
,this
会被当作变量一直向上级作用域查找,直至找到为止,经常导致Uncaught TypeError:Cannot read property of undefined
或Uncaught TypeError:this.myMethod is not a function
之类的错误。
2、生命周期详解
2.1、生命周期图示

2.2、理解生命周期函数/钩子
生命周期钩子:即生命周期函数,也即是生命周期事件的别名而已。
主要的生命周期函数分类:
- 创建/初始化阶段的生命周期函数(4个函数:
beforeCreate()
、created()
、beforeMount()
、mounted()
); - 运行/更新阶段的生命周期函数(2个函数:
beforeUpdate()
、updated()
); - 销毁阶段的生命周期函数(2个函数:
beforeDestroy()
、destroyed()
);
2.3、生命周期函数执行流程
(1)、当引入vue.js
之后,Vue
就会成为全局变量,我们可以通过new Vue()
创建一个Vue
实例(创建Vue
实例)
(2)、初始化事件和生命周期函数,没有执行(初始化Vue
实例)
(3)、生命周期函数:beforeCreate()
,在实例初始化之后,配置对象创建之前被调用
表明:配置项都没有执行,data
、methods
、computed
、filters
...都无法访问。
(4)、初始化、注入、校验,创建配置对象。
(5)、生命周期函数:created()
,配置对象创建之后被调用。
表明:data
、methods
、computed
、filters
配置项都可以访问了。但是el
,还没有绑定,vm
实例挂载还没有开始。 created()
生命周期函数中是最早可以操作data
里面的数据的地方。
(6)、是否指定el
配置项:
是:继续向下执行
否:判断是否调用vm.$mount(el)
,如果调用了才继续向下执行。
要么指定了el
配置项,要么调用了vm.$mount(el)
,否则必须继续向下执行。
(7)、是否指定了template
选项:
是:将template
编译到render
函数中,使用template
替代挂载点
否:将el
外部的HTML
作为template
编译,把el
挂载点作为template
模板
(8)、生命周期函数:beforeMount()
:挂载开始之前被调用,此时,数据还没有被真正放到模板中,在这里还可以看到原始的模版数据,比如{{xxx}}
...
(9)、创建vm.$el
并用其替代el
,用編译好的内容(指令和插值表达式替换后的内容)替代el挂载点里面的模版内容。
(10)、生命周期函数:mounted()
,挂载完成之后调用,可以获取到真正渲染到页面中的真实数据。 mounted()
是用到的最多的生命周期函数,用来发送一些异步请求。
(11)、经过上面一系列过程,脱离了创建阶段,挂载完毕。
(12)、生命周期函数:beforeUpdate()
,实时监听数据变化(双向监听),一旦data
中的数据发生改变(M/V)就会调用。到这里还没有进行数据的更新(View
和Model
数据还没同步)。
(13)、虚拟DOM
重新渲染,并应用更新。
(14)、生命周期函数:updated()
,更新完成之后调用,DOM
和data
同步
(15)、档调用vm.$destroy()
函数时,进行销毁阶段。
(16)、生命周期函数:beforeDestroy()
,销毁之前。
(17)、解除绑定销毁子组件以及事件监听器。简单来说就是销毁Vue实例对象以及Vue里面的配置对象。
(18)、生命周期函数:destroyed()
,销毁完毕。
3、生命周期函数使用
3.1、beforeCreate()函数执行
beforeCreate()
是在创建配置对象之前调用,那么肯定无法使用data
、methods
、computed
...
<div id="root">
{{msg}}
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
beforeCreate() {
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
}
});
</script>
运行结果:

3.2、created()函数执行
配置对象创建之后调用,那么我们可以调用除了el
以外的所有内容。
<div id="root">
{{msg}}
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
created: function(){
console.log("created()生命周期函数执行了");
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
console.log("============created()生命周期函数执行结束了==========");
},
});
</script>
运行结果:

3.3、beforeMount()函数
beforeMount()
是在挂载之前被调用,编译之后的模版还没有替换挂载点里面的内容。
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
beforeMount() {
console.log("beforeMount()生命周期函数执行了");
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
console.log("============beforeMount()生命周期函数执行结束了==========");
},
});
</script>
运行结果:

3.4、mounted()函数
mounted()
实例挂载完成后执行。
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
//挂载完成
mounted() {
console.log("mounted()生命周期函数执行了");
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
let html = document.getElementById("root").innerHTML;
console.log(html);
console.log("============mounted()生命周期函数执行结束了==========");
},
});
</script>
运行结果:

3.5、beforeUpdate()函数
- 页面刷新,数据没有发生改变,该函数不会执行,只有当data发生改变后,才会进入该函数;
- 表示data中的数据已经被更新,但是你仅更新了内存中的vm,还没有更新到DOM树;
- 可以访问data,method,可以访问到最新的值;
- DOM中的元素的值,也可以被访问到,但是获取的是改变之前的旧值;
- Vue实例处于运行阶段;
<div id="root">
<p>{{msg}}</p>
<button @click="modifyMsg">修改msg</button>
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
},
modifyMsg(){
this.msg = 'msg修改后的数据';
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
//更新数据之前
beforeUpdate(){
console.log("beforeUpdate()生命周期函数执行了");
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
let html = document.getElementById("root").innerHTML;
console.log(html);
console.log("============beforeUpdate()生命周期函数执行结束了==========");
}
});
</script>
档点击修改msg按钮的时候,beforeUpdate()
函数执行,执行结果:

3.6、updated函数
- 表示data和DOM树的数据都是最新的;
- 可以访问data,methods,DOM元素的值可以访问到最新值;
- Vue实例处于运行阶段;
当更新完成后,执行updated,数据已经更改完成,DOM也重新render完成。
<div id="root">
<p>{{msg}}</p>
<button @click="modifyMsg">修改msg</button>
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data:{
msg: 'Hello Vuejs'
},
methods: {
fn1(){
console.log("methods里面的函数fn1执行了......")
},
modifyMsg(){
this.msg = 'msg修改后的数据';
}
},
computed:{
reverseMsg(){
return this.msg.split('').reverse().join('');
}
},
//在vue实例里面显式定义生命周期函数
//更新数据之后
updated(){
console.log("updated()生命周期函数执行了");
console.log("data里面的数据: "+ this.msg);
console.log("计算属性中的数据: "+ this.reverseMsg);
//methods里面的函数
this.fn1();
let html = document.getElementById("root").innerHTML;
console.log(html);
console.log("============updated()生命周期函数执行结束了==========");
}
});
</script>
运行结果:

3.7、beforeDestory()和destoryed()
当经过某种途径调用$destroy()
方法后,立即执行beforeDestroy
,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等。
当执行beforeDestory()
方法时,Vue实例就已经从运行阶段,进入到了销毁阶段;组件的数据绑定、监听..去掉后只剩下DOM空壳,这个时候,执行destroyed,在这里做善后工作也可以。当执行beforeDestory()
的时候,实例身上所有的data和methods以及过滤器、指令等都处于可用状态,此时,还没有真正执行销毁过程。当执行到destroyed()
方法时,Vue组件里的过滤器、指令、方法都不可用了。

3、常用生命周期方法
created()/mounted()
:发送ajax请求,启动定时器等异步任务;beforeDestory()
:做收尾工作,如:清除定时器;