每个vue在被创建之前,都要经过一系列的初始化过程,这个过程就是vue的生命周期
在vue一整个生命周期中会员很多钩子函数提供给我们,再vue生命周期的不同时刻进行操作
vue父子生命周期执行顺序
- 1,加载渲染过程
父子组件在加载的时候,执行的先后顺序为父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted。
- 2,子组件更新过程
父beforeUpdate ---> 子beforeUpdate ---> 子updated ---> 父updated
- 3,父组件更新过程
父beforeUpdate ---> 父updated
- 4,销毁过程
父beforeDestroy ---> 子beforeDestroy ---> 子destroyed ---> 父destroyed
创建期间的生命周期函数
-
beforeCreated
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用,还没有初始化好 data 和 methods 属性
-
created
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用, 此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调。 但是还没有开始 DOM 编译,$el 还不存在,但是实例存在,即this.a存在,可打印出来, 触发vue的created事件以后,this便指向vue实例
-
beforMount
在挂载开始之前被调用:相关的 render 函数首次被调用。此时已经完成了模板的编译,但是还没有挂载到页面中
该钩子在服务器端渲染期间不被调用
-
mounted
实例被挂载后调用,这时 el 被新创建的 vm.el 也在文档内。
注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick:
运行期间的生命周期函数
-
beforUpdate
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
-
updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick:
销毁期间的生命周期函
- beforDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。 8. destroy
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。该钩子在服务器端渲染期间不被调用 9. activated
被 keep-alive 缓存的组件激活时调用。该钩子在服务器端渲染期间不被调用
10. deactivated
被 keep-alive 缓存的组件停用时调用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Vue的生命周期'
},
beforeCreate: function() {
console.group('------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) //undefined
},
created: function() {
console.group('------created创建完毕状态------');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化 , [object Object]
console.log("%c%s", "color:red","message: " + this.message); //已被初始化, vue生命周期
},
beforeMount: function() {
console.group('------beforeMount挂载前状态------');
console.log("%c%s", "color:red","el : " + (this.$el)); //undefined
console.log(this.$el);//undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化, [object Object]
console.log("%c%s", "color:red","message: " + this.message); //已被初始化, vue生命周期
},
mounted: function() {
console.group('------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('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);//[object HTMLDivElement]
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
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);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
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);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
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)
}
})
</script>
</html>
1,在beforCreated 和created钩子函数之间的生命周期
在这个生命周期之间,进行初始化时间,进行数据观测,可以看到在created的时候数据已经和data属性进行绑定(放在data中的属性当值发生改变的同事,视图也会改变)
注意:此时没有el
2,created钩子函数和beforeMount间的生命周期
在这个阶段发生的事情比较多
首先会判断对象是否有el选项,如果有就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el)
// 此时注释点代码
el: '#app'
可以看到运行到created的时候停止了,如果后面继续调用vm.$mount(el),可以发现代码继续向下执行了
vm.$mount(el) // 这个el参数就是挂载的dom节点
继续往下看,template参数选项是否对生命周期影响
- 如果vue实例对象中有template参数选项,则将其作为模板编译成render函数
- 如果没有template选项,则将外部HTML作为模板编译
- 可以看到template中的模板优先级高于outer Html的优先级
// 修改vue中的代码
<body>
<div id="app">
<h1>{{message + '这是在outer HTML中的'}}</h1>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
template: "<h1>{{message +'这是在 template 中的'}}</h1>" //在vue配置中修改的
data: {
message: 'Vue的生命周期'
},
执行结果显示,vue的生命周期,这是在template中的,如果注释掉template的选项,则会显示出: vue的生命周期,这是在outer HTML中的
这样就可以知道为什么el的判断要在templa之前了,因为vue需要通过el找到对应的outer template
在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入jsx
new Vue({
el: '#app',
render: function(createElement) {
return createElement('h1', 'this is createElement')
}
})
可以看到页面渲染的是this is createElement
- 所以综合排名优先级: render函数选项 > templa选项 > outer HTML
3, beforeMount 和 mounted狗子函数的生命周期
此时给vue实例添加$el成员,并且替换掉挂在的DOM元素
4,mounted
在mounted之前,h1中还是通过{{message}}占位的,因为此时还有挂载到页面上,还是js中的虚拟dom形式存在的,在mounted之后可以看到h1中内容发生了变化
5,beforeUpdate和updated钩子函数间的生命周期
当vue发现data中的数据发生了改变,会触发对应组件的重新渲染,先后调用beforeUpdate和updated
进入某个路由对应的组件的时候,我们会触发哪些类型的周期呢, 我们看到执行的顺序为
路由勾子 (beforeEach、beforeRouteEnter、afterEach)
根组件 (beforeCreate、created、beforeMount)
组件 (beforeCreate、created、beforeMount)
指令 (bind、inserted)
组件 mounted
根组件 mounted
beforeRouteEnter的next的回调
nextTick