记vuejs生命周期一次体验

>>>点击获取更多文章<<<

提示:下面体验的 vue version 是 ^2.5.13

一.Vue生命周期简介

官网:https://cn.vuejs.org/v2/api/#beforeCreate
Vue实例从创建到销毁的过程,就是生命周期。详细来说也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。
首先我们来看一下官网的生命周期图(我自己做了一点点注释):

alt text

Vue提供给我们的钩子为上图的红色的文字

二.钩子详解

注释:下面代码使用组件方式

1.beforeCreate

在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。

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
<style>

</style>

<template>
<div>
</div>
</template>

<script>
export default {
name: 'Test',
data(){
return{
message:'this is mseeage'
}
},
watch:{
message:function(){
console.log('watch:','message 变了')
}
},
methods: {
init:function(){
console.log('这是初始化方法')
}
},
//我们在beforeCreate钩子中调用Vue的data和method
beforeCreate:function(){
console.log("beforeCreate",this.message);
this.init();
}
}
</script>

我们在上面的例子中在的beforeCreate钩子中调用Vue的data和method,来看一下结果:

alt text

可以看到Vue中的data和方法都是去不到的,并且是在wath之前执行

2.created

实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<style>

</style>

<template>
<div>

<ul>
<li v-for="(item,index) in list" :key="index">{{ item }} -- {{message}}</li>
</ul>

<p ref="pnode">p1</p>
<p id="myAnchor">p1</p>
<p>p1</p>

</div>
</template>

<script>
export default {
name: 'Test',
data () {
return {
message:'this is 张炳 message!嘿嘿!',
list:['aaaaaaaa','bbbbbbb','ccccccc']
}
},
//时刻监测数据message的变化,一但那变化就会吊该函数
watch:{
//message必须和监测的data名字一样
message:function(){
console.log('watch:','message 变了')
}
},
methods: {
foo:function(){
console.log('foo : ','这是初始化方法')
}
},
//created钩子
created:function(){
//调用Vue的data
console.log("created : ",this.message);
//调用Vue方法
this.foo();

console.log(this.$refs); //是空,更别说 获取到 this.$refs.pnode了

//无法获取到个数
console.log('li数量:',document.getElementsByTagName('li').length);

console.log('p个数:',document.getElementsByTagName('p').length);

//均无法获取到dom,无法设置
document.getElementsByTagName('p')[0].innerHTML = 'hello! zhangbing'
document.getElementById('myAnchor').innerHTML="bye! zhangbing";
},

}
</script>

alt text

可以看到:created钩子可以获取Vue的data,可以调用Vue方法 , 但 挂载阶段还没开始,$el 属性目前不可见。 this.$refs为空对象,获取dom的个数,和设置dom的innerHTML均失效,出现报错。

3.beforeMount

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
<style>

</style>

<template>
<div>
<ul>
<li v-for="(item,index) in list" :key="index">{{ item }} -- {{message}}</li>
</ul>

<p ref="pnode">p1</p>
<p id="myAnchor">p1</p>
<p>p1</p>

</div>
</template>

<script>
export default {
name: 'Test',
data () {
return {
message:'this is 张炳 message!嘿嘿!',
list:['aaaaaaaa','bbbbbbb','ccccccc']
}
},
beforeMount: function () {
console.log('beforeMount: li数量:',document.getElementsByTagName('li').length);
console.log('beforeMount: p数量:',document.getElementsByTagName('p').length);
}
}
</script>

alt text

官方文档:在挂载开始之前被调用:相关的 render 函数首次被调用。 beforeMount挂载钩子,此时还没有生成HTML到页面中,没法获取 dom的数量。

4.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
<style>
</style>
<template>
<div>
<ul>
<li v-for="(item,index) in list" :key="index">{{ item }} -- {{message}}</li>
</ul>
<p ref="pnode">p1</p>
<p id="myAnchor">p1</p>
<p>p1</p>
</div>
</template>
<script>
export default {
name: 'Test',
data () {
return {
message:'this is 张炳 message!嘿嘿!',
list:['aaaaaaaa','bbbbbbb','ccccccc']
}
},
mounted: function () {
console.log('mounted: li数量:',document.getElementsByTagName('li').length);
console.log('mounted: p数量:',document.getElementsByTagName('p').length);
}
}
</script>

alt text

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。看到可以正常获取到dom的个数了

5.beforeUpdate

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
<style>
</style>
<template>
<div>
<ul>
<li v-for="(item,index) in list" :key="index">{{ item }} -- {{message}}</li>
</ul>
<p ref="pnode"> p1</p>
<p id="myAnchor">p1</p>
<p>p1</p>

<input type="button" @click="changeMessage" value="更改数据">
</div>
</template>
<script>
export default {
name: 'Test',
data () {
return {
message:'this is 张炳 message!嘿嘿!',
list:['aaaaaaaa','bbbbbbb','ccccccc']
}
},
beforeUpdate: function () {
console.log('beforeUpdate 钩子执行...');
console.log('beforeUpdate:'+this.message);
},
methods:{
changeMessage(){
this.message = 'hello. 张炳,我更改数据了'+ Math.random();
}
}
}
</script>

alt text

点击按钮 3次,出现上面的图;

数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。要明确这句话:意思是数据更新后了调用这个钩子,但是在渲染虚拟dom之前!!!所以你看到的 chrome 调控台的数据也是 数据更新后的数据!

同时,你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。 当我们更改Vue的任何数据,都会触发该函数。

6.updated

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
<style>
</style>
<template>
<div>
<ul>
<li v-for="(item,index) in list" :key="index">{{ item }} -- {{message}}</li>
</ul>
<p ref="pnode"> p1</p>
<p id="myAnchor">p1</p>
<p>p1</p>

<input type="button" @click="changeMessage" value="更改数据">
</div>
</template>
<script>
export default {
name: 'Test',
data () {
return {
message:'this is 张炳 message!嘿嘿!',
list:['aaaaaaaa','bbbbbbb','ccccccc']
}
},
updated: function () {
console.log('updated 钩子执行...');
console.log('updated:'+this.message);
},
methods:{
changeMessage(){
this.message = 'hello. 张炳,我更改数据了'+ Math.random();
}
}
}
</script>

alt text

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环 。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。

7.beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。

8.destroyed

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
</div>
<script type="text/javascript">
//实例化Vue
var app = new Vue({
el:'#app',
data:{
message:'this is mseeage',
},
beforeDestroy: function () {
console.log('beforeDestroy 钩子执行...',this.message)
},
destroyed: function () {
console.log('destroyed 钩子执行...',this.message)
}
})
//销毁Vue实例,触发beforeDestroy和destroyed函数
app.$destroy()
</script>

alt text