生命周期
生命周期
概述
生命周期又名生命周期回调函数、生命周期函数、生命周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的 this 指向是 vm 或组件实例对象。
总结
beforecreate
: 可以在这加个loading事件mounted
发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作【发起后端请求,拿回数据,配合路由钩子做一些事情】beforeDestroy
清除定时器、解绑自定义事件、取消订阅消息等收尾工作【你确认删除XX吗?】created
:在这结束loading,还做一些初始数据的获取,实现函数自执行destroyed
:当前组件已被删除,清空相关内容activated
与deactivated
:路由组件独有的钩子函数nextTick
:下次更新 DOM 后触发。
生命周期图
挂载的流程
绿框1
初始化:生命周期、事件,但数据代理还未开始。
beforeCreated 钩子 (创建数据代理)
还无法访问 data 中的数据,methods 中的方法
绿框2
初始化:数据监测、数据代理。
created 钩子
完成数据监测,数据代理,可以访问 data 中的数据,methods 中的方法
第一个方框
此阶段 Vue 开始解析模板,生成虚拟 DOM(内存中),页面还未显示解析好的内容。
分析:
- 如果没有传入 el 选项,也没有外部调用 mount() Vue 程序就会停止,等待传入 el 再往下走
- template:把它当做 HTML 模板来解析(组件就是这样搞的)
beforeMount (挂载真实 DOM)
此时:
- 页面呈现的是未经 Vue 编译的 DOM 结构。
- 所有对 DOM 的操作,最终都不奏效。
绿框3
将内存中的虚拟 DOM 转为真实 DOM 插入页面。
mounted
Vue 完成模板的解析并把初始的真实 DOM 元素放入页面后调用 mounted (挂载完毕)。只调用一次。
此时:
- 页面中呈现的是经过 Vue 编译的 DOM。
- 对 DOM 的操作均有效(尽可能避免)。
至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作。
this.$el 旧的真实 DOM
测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue实例的生命周期</title>
</head>
<body>
<div id="app">
<h1>测试生命周期</h1>
<div>{{msg}}</div>
<hr>
<h3>测试beforeUpdate和update两个钩子函数</h3>
<button @click="handlerUpdate">更新数据</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
msg: "12345"
},
methods: {
handlerUpdate() {
this.msg=this.msg.split("").reverse().join("")
}
},
//按照示意图依次调用
beforeCreate(){
console.log("调用了beforeCreate钩子函数");
},
created(){
console.log("调用了created钩子函数");
},
beforeMount(){
console.log('调用了beforeMount钩子函数');
},
mounted(){
console.log('调用了mounted钩子函数');
},
beforeUpdate(){
console.log("调用了beforeUpdate钩子函数")
},
updated(){
console.log("调用了updated钩子函数");
},
beforeDestroy(){
console.log("调用了beforeDestroy钩子函数");
},
destroyed(){
console.log("调用了destroyed钩子函数");
}
})
</script>
</body>
</html>
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
如图所示:
初始化页面依次调用了:
- 调用了beforeCreate钩子函数
- 调用了created钩子函数
- 调用了beforeMount钩子函数
- 调用了mounted钩子函数
点击更新数据后:
12345
变成了54321
,此时调用了:
- 调用了beforeUpdate钩子函数
- 调用了updated钩子函数
打开F12控制台
直接输入app.$destroy()
主动销毁Vue实例调用:
- 调用了beforeDestroy钩子函数
- 调用了destroyed钩子函数
el选项对生命周期影响
有el选项
new Vue({
el: '#app',
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:
无el选项
new Vue({
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
结果:
var app = new Vue({
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
app.$mount('#app')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:
template和HTML优先级
同时使用template和HTML,查看优先级:
<h1>测试template和HTML的优先级</h1>
<div id="app">
<p>HTML优先</p>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
msg:"template优先"
},
template:"<p>{{msg}}</p>",
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
结果:
结论
- 如果Vue实例对象中有template参数选项,则将其作为模板编译成render函数
- 如果没有template参数选项,则将外部的HTML作为模板编译(template),也就是说,template参数选项的优先级要比外部的HTML高
- 如果1,2条件都不具备,则报错
注意
- Vue需要通过el去找对应的template,Vue实例通过el的参数,首先找自己有没有template,如果没有再去找外部的html,找到后将其编译成render函数。
- 也可以直接调用render (opens new window)选项,优先级:
render函数选项 > template参数 > 外部HTML
。
new Vue({
el: '#app',
render (createElement) {
return (....)
}
})
2
3
4
5
6
beforeMount和mounted钩子函数间的生命周期
beforeMount
载入前(完成了data和el数据初始化),但是页面中的内容还是vue中的占位符,data中的message信息没有被挂在到Dom节点中,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取。
Mount
载入后html已经渲染(ajax请求可以放在这个函数中),把vue实例中的data里的message挂载到DOM节点中去
这里两个钩子函数间是载入数据。
beforeUpdate钩子函数和updated钩子函数间的生命周期
在Vue中,修改数据会导致重新渲染,依次调用beforeUpdate钩子函数和updated钩子函数
如果待修改的数据没有载入模板中,不会调用这里两个钩子函数
var app = new Vue({
el: '#app',
data: {
msg: 1
},
template: '<div id="app"><p></p></div>',
beforeUpdate: function () {
console.log('调用了beforeUpdate钩子函数')
},
updated: function () {
console.log('调用了updated钩子函数')
}
})
app.msg = 2
2
3
4
5
6
7
8
9
10
11
12
13
14
结果:
如果绑定了数据,会调用两个钩子函数:
<h1>测试有数据绑定修改数据,钩子函数调用情况</h1>
<div id="app">
</div>
<script>
var app = new Vue({
el:"#app",
template:"<p>{{msg}}</p>",
data:{
msg:"原数据"
},
beforeUpdate: function () {
console.log("调用了beforeUpdate钩子函数")
},
updated: function () {
console.log("调用了updated钩子函数");
},
});
app.msg = "数据被修改了";
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
结果:
注意只有写入模板的数据才会被追踪
beforeDestroy和destroyed钩子函数间的生命周期
beforeDestroy
销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等…’)
destroyed
销毁后 (Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件
关于销毁 Vue 实例
- 销毁后借助 Vue 开发者工具看不到任何信息
- 销毁后自定义事件会失效,但原生 DOM 事件依然有效
- 一般不会在 beforeDestroy 操作数据,因为即便操作数据,也不会再触发更新流程了
更新流程
beforeUpdate
此时:数据是新的,但页面是引旧的。
即:页面尚未和数据保持同步。
绿框
根据新数据,生成新的虚拟 DOM,随后与旧的虚拟 DOM 进行比较,最终完成页面更新。
即:完成了Model → View 的更新
updated
此时:数据是新的,页面也是新的,即:页面和数据保持同步。
销毁流程
销毁后 VM 对象销毁,但页面还在,只是没有响应了。
原生 DOM 事件还是可以使用,自定义事件不在了
beforeDestory
此时:vm 中所有的:data、methods、指令等等,都做处于可用状态,马上要执行销毁过程,一般在此阶段**:关闭定时器**、取消订阅消息、解绑自定义事件等收尾操作。
但是这个阶段对数据进行修改,DOM 不会更新。
生命周期
概述
生命周期又名生命周期回调函数、生命周期函数、生命周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的 this 指向是 vm 或组件实例对象。
总结
beforecreate
: 可以在这加个loading事件mounted
发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作【发起后端请求,拿回数据,配合路由钩子做一些事情】beforeDestroy
清除定时器、解绑自定义事件、取消订阅消息等收尾工作【你确认删除XX吗?】created
:在这结束loading,还做一些初始数据的获取,实现函数自执行destroyed
:当前组件已被删除,清空相关内容activated
与deactivated
:路由组件独有的钩子函数nextTick
:下次更新 DOM 后触发。
生命周期图
挂载的流程
绿框1
初始化:生命周期、事件,但数据代理还未开始。
beforeCreated 钩子 (创建数据代理)
还无法访问 data 中的数据,methods 中的方法
绿框2
初始化:数据监测、数据代理。
created 钩子
完成数据监测,数据代理,可以访问 data 中的数据,methods 中的方法
第一个方框
此阶段 Vue 开始解析模板,生成虚拟 DOM(内存中),页面还未显示解析好的内容。
分析:
- 如果没有传入 el 选项,也没有外部调用 mount() Vue 程序就会停止,等待传入 el 再往下走
- template:把它当做 HTML 模板来解析(组件就是这样搞的)
beforeMount (挂载真实 DOM)
此时:
- 页面呈现的是未经 Vue 编译的 DOM 结构。
- 所有对 DOM 的操作,最终都不奏效。
绿框3
将内存中的虚拟 DOM 转为真实 DOM 插入页面。
mounted
Vue 完成模板的解析并把初始的真实 DOM 元素放入页面后调用 mounted (挂载完毕)。只调用一次。
此时:
- 页面中呈现的是经过 Vue 编译的 DOM。
- 对 DOM 的操作均有效(尽可能避免)。
至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作。
this.$el 旧的真实 DOM
测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue实例的生命周期</title>
</head>
<body>
<div id="app">
<h1>测试生命周期</h1>
<div>{{msg}}</div>
<hr>
<h3>测试beforeUpdate和update两个钩子函数</h3>
<button @click="handlerUpdate">更新数据</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
msg: "12345"
},
methods: {
handlerUpdate() {
this.msg=this.msg.split("").reverse().join("")
}
},
//按照示意图依次调用
beforeCreate(){
console.log("调用了beforeCreate钩子函数");
},
created(){
console.log("调用了created钩子函数");
},
beforeMount(){
console.log('调用了beforeMount钩子函数');
},
mounted(){
console.log('调用了mounted钩子函数');
},
beforeUpdate(){
console.log("调用了beforeUpdate钩子函数")
},
updated(){
console.log("调用了updated钩子函数");
},
beforeDestroy(){
console.log("调用了beforeDestroy钩子函数");
},
destroyed(){
console.log("调用了destroyed钩子函数");
}
})
</script>
</body>
</html>
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
如图所示:
初始化页面依次调用了:
- 调用了beforeCreate钩子函数
- 调用了created钩子函数
- 调用了beforeMount钩子函数
- 调用了mounted钩子函数
点击更新数据后:
12345
变成了54321
,此时调用了:
- 调用了beforeUpdate钩子函数
- 调用了updated钩子函数
打开F12控制台
直接输入app.$destroy()
主动销毁Vue实例调用:
- 调用了beforeDestroy钩子函数
- 调用了destroyed钩子函数
el选项对生命周期影响
有el选项
new Vue({
el: '#app',
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:
无el选项
new Vue({
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
结果:
var app = new Vue({
beforeCreate: function () {
console.log('调用了beforeCreat钩子函数')
},
created: function () {
console.log('调用了created钩子函数')
},
beforeMount: function () {
console.log('调用了beforeMount钩子函数')
},
mounted: function () {
console.log('调用了mounted钩子函数')
}
})
app.$mount('#app')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:
template和HTML优先级
同时使用template和HTML,查看优先级:
<h1>测试template和HTML的优先级</h1>
<div id="app">
<p>HTML优先</p>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
msg:"template优先"
},
template:"<p>{{msg}}</p>",
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
结果:
结论
- 如果Vue实例对象中有template参数选项,则将其作为模板编译成render函数
- 如果没有template参数选项,则将外部的HTML作为模板编译(template),也就是说,template参数选项的优先级要比外部的HTML高
- 如果1,2条件都不具备,则报错
注意
- Vue需要通过el去找对应的template,Vue实例通过el的参数,首先找自己有没有template,如果没有再去找外部的html,找到后将其编译成render函数。
- 也可以直接调用render (opens new window)选项,优先级:
render函数选项 > template参数 > 外部HTML
。
new Vue({
el: '#app',
render (createElement) {
return (....)
}
})
2
3
4
5
6
beforeMount和mounted钩子函数间的生命周期
beforeMount
载入前(完成了data和el数据初始化),但是页面中的内容还是vue中的占位符,data中的message信息没有被挂在到Dom节点中,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取。
Mount
载入后html已经渲染(ajax请求可以放在这个函数中),把vue实例中的data里的message挂载到DOM节点中去
这里两个钩子函数间是载入数据。
beforeUpdate钩子函数和updated钩子函数间的生命周期
在Vue中,修改数据会导致重新渲染,依次调用beforeUpdate钩子函数和updated钩子函数
如果待修改的数据没有载入模板中,不会调用这里两个钩子函数
var app = new Vue({
el: '#app',
data: {
msg: 1
},
template: '<div id="app"><p></p></div>',
beforeUpdate: function () {
console.log('调用了beforeUpdate钩子函数')
},
updated: function () {
console.log('调用了updated钩子函数')
}
})
app.msg = 2
2
3
4
5
6
7
8
9
10
11
12
13
14
结果:
如果绑定了数据,会调用两个钩子函数:
<h1>测试有数据绑定修改数据,钩子函数调用情况</h1>
<div id="app">
</div>
<script>
var app = new Vue({
el:"#app",
template:"<p>{{msg}}</p>",
data:{
msg:"原数据"
},
beforeUpdate: function () {
console.log("调用了beforeUpdate钩子函数")
},
updated: function () {
console.log("调用了updated钩子函数");
},
});
app.msg = "数据被修改了";
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
结果:
注意只有写入模板的数据才会被追踪
beforeDestroy和destroyed钩子函数间的生命周期
beforeDestroy
销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等…’)
destroyed
销毁后 (Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件
关于销毁 Vue 实例
- 销毁后借助 Vue 开发者工具看不到任何信息
- 销毁后自定义事件会失效,但原生 DOM 事件依然有效
- 一般不会在 beforeDestroy 操作数据,因为即便操作数据,也不会再触发更新流程了
更新流程
beforeUpdate
此时:数据是新的,但页面是引旧的。
即:页面尚未和数据保持同步。
绿框
根据新数据,生成新的虚拟 DOM,随后与旧的虚拟 DOM 进行比较,最终完成页面更新。
即:完成了Model → View 的更新
updated
此时:数据是新的,页面也是新的,即:页面和数据保持同步。
销毁流程
销毁后 VM 对象销毁,但页面还在,只是没有响应了。
原生 DOM 事件还是可以使用,自定义事件不在了
beforeDestory
此时:vm 中所有的:data、methods、指令等等,都做处于可用状态,马上要执行销毁过程,一般在此阶段**:关闭定时器**、取消订阅消息、解绑自定义事件等收尾操作。
但是这个阶段对数据进行修改,DOM 不会更新。