前言
开始正文之前,我们先回想以下几个问题:
- 生命周期是什么?
- Vue的生命周期有哪些?
- 不同的周期又是什么含义
- 它们的执行顺序是怎样的?
一、生命周期
1.1 生命周期是什么?
生命周期:Life Cycle。其基本涵义可以通俗地理解为“从摇篮到坟墓”(Cradle-to-Grave)的整个过程
在Vue中实例从创建到销毁的过程就是生命周期,即指从创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程我们可以把组件比喻成工厂里面的一条流水线,每个工人(生命周期)站在各自的岗位,当任务流转到工人身边的时候,工人就开始工作。
1.2 生命周期的作用是什么?
作用:让开发者有机会在特定阶段运行自己的代码
二、Vue的生命周期
2.1 Vue生命周期
Vue生命周期可划分的阶段:
-
创建前后
-
beforeCreate: 组件实例被创建之初
执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务
-
created: 组件实例已经完全创建
组件初始化完毕,各种数据可以使用,常用于异步数据获取
-
-
挂载前后
-
beforeMount:组件挂载之前
未执行渲染、更新,DOM未创建,已经完成了data和el数据初始化,但是页面中的内容还是Vue中的占位符,data中的message信息没有被挂载到BOM节点中,在这里可以在渲染前最后一次更改数据的机会,不会触发其它钩子函数
-
mounted:组件挂载到实例上去之后
初始化结束,DOM已创建,可用于访问数据和DOM元素
-
-
更新前后
-
beforeUpdate:data数据发生变化,更新之前。同时,我们需要知道,不是所有data数据发生变化都会触发该钩子函数的。因为beforedata 是针对视图层的数据
更新前,可以用于获取更新前各种状态
-
updated:data数据更新之后
更新后,所有状态已是最新
-
-
销毁前后(关闭页面或关闭浏览器)
-
beforeDestory:组件实例销毁之前,此时我们仍然可以使用data与method方法
销毁前,可用于一些定时或订阅的取消
-
destoryed:组件实例销毁之后,此时组件的data和method都已经被销毁
组件已销毁,可用于一些定时器或监听的取消
-
-
特殊场景
- activated: keep-alive 缓存的组件激活时
- deactivated:keep-alive 缓存的组件停用时
- errorCaptured:捕获来自子孙组件的错误时被调用
- 收到的参数:
- 错误对象
- 发生错误的组件实例
- 说明错误来源类型的信息字符串
- 错误的来源有:
- 组件渲染
- 事件处理器
- 生命周期钩子
- setup() 函数
- 侦听器
- 自定义指令钩子
- 过渡钩子
- 使用场景:
- 在
errorCaptured中更改组件状态为用户显示一个错误状态(注意不要让错误状态再次渲染导致本次错误的内容,否则组件会陷入无限循环) - 在
errorCaptured中可以通过返回false来阻止错误继续向上传递
- 在
- 错误传递规则:
- 默认情况下,所有的错误都会被发送到应用级的
app.config.errorHandler(前提是这个函数已经定义),这样这些错误都能在一个统一的地方报告给分析服务 - 如果组件的继承链或者组件链上存在多个
errorCaptured钩子,对于同一个错误,这些钩子会被按从底至上的顺序--调用。这个过程被称为“向上传递”,类似于原生DOM事件的冒泡机制 - 如果
errorCaptured钩子本身抛出一个错误,那么这个错误和原生捕获到的错误都将被发送到app.config.errorHandler errorCaptured钩子可以通过返回false来阻止错误继续向上传递。即表示“这个错误已经被处理了,应该被忽略”,它将阻止其它的errorCaptured钩子或app.config.errorHandler因这个错误被调用
- 默认情况下,所有的错误都会被发送到应用级的
- 收到的参数:
2.2 生命周期图示
- beforeCreate -> created:初始化 vue 实例,进行数据检测
- created:
- 完成数据观测,属性与方法的运算,watch、event 事件回调的配置
- 可调用 methods 中的方法,访问和修改 data 数据触发响应式渲染 dom,可通过 computed 和 watch 完成数据计算
- 此时
vm.$el并没有被创建
- created -> beforeMount
- 判断是否存在
el选项,若不存在则停止编译,直到调用vm.$mount(el)才会继续编译 - 优先级:
render > template > outerHTML vm.el获取到的是挂载 DOM 的
- 判断是否存在
- beforeMount
- 在此阶段可获取到vm.el
- 此阶段vm.el虽已完成DOM初始化,但并未挂载在el选项上
- beforeMount -> mounted
- 此阶段vm.el完成挂载,vm.$el生成的DOM替换了el选项所对应的DOM
- mounted
- vm.el已完成DOM的挂载与渲染,此刻打印vm.$el,发现之前的挂载点及内容已被替换成新的DOM
- beforeUpdate
- 更新的数据必须是被渲染在模板上的(el、template、render之一)
- 此时view层还未更新
- 若在beforeUpdate中再次修改数据,不会再次触发更新方法
- updated
- 完成view层的更新
- 若在updated中再次修改数据,会再次触发更新方法(beforeUpdate、updated)
- beforeDestroy
- 实例被销毁前调用,此时实例属性与方法仍可访问
- destroyed
- 完全销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器
- 并不能清除DOM,仅仅销毁实例
2.3 生命周期详细图解
<script>
export default {
// 在实例初始化之后,数据观测和事件配置之前被调用
beforeCreate(){
console.log('beforeCreate----创建前');
},
// 实例已经创建完成之后被调用
created(){
console.log('created----创建之后');
},
// 页面准备挂载时候被调用,此时相关的渲染函数首次被调用
beforeMount(){
console.log('beforeMount----挂载开始');
},
// 挂在完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次。
mounted(){
console.log('mounted----挂载完成');
},
// 数据更新之前被调用
beforeUpdate(){
console.log('beforeUpdate----更新之前被调用');
},
//数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子
updated(){
console.log('updated----更新后');
},
// 我们将要销毁整个页面或实例时调用
beforeDestroy(){
console.log('beforeDestroy----销毁前');
},
// 我们的整个页面或实例被销毁之后调用
destroyed(){
console.log('destroyed----销毁后');
},
// 被 keep-alive 缓存的组件激活时调用
activated(){
console.log('activated');
},
// deactivated配合keep-alive来使用
// 使用了keep-alive就不会调用beforeDestory和destoryed钩子了
// 因为组件没有被销毁,而是被缓存起来了
// 所以deactivated钩子可以看做是beforeDestory和destoryed的替代
deactivated(){
console.log('deactivated');
}
}
</script>
三、Vue生命周期知多少
3.1 vue生命周期钩子函数为什么不能使用箭头函数?
Vue生命周期钩子会自动绑定this上下文到实例中,因此我们可以访问数据,对property和方法进行运算。这意味着我们不能使用箭头函数来定义一个生命周期方法,因为箭头函数绑定了父级上下文,所以 this 不会指向预期的组件实例。
3.2 数据请求在created和mouted的区别?
区别:
- 执行时机:
create比mounted的更早 - DOM节点:
create是在组件实例一旦创建完成的时候立刻调用,这时页面 DOM 节点尚未生成;mounted是在页面 DOM 节点渲染完毕后就立刻执行的,这时页面 DOM 节点已生成
相同点:
- 都能拿到实例对象的属性和方法
总结:
请求放在mounted中可能导致页面白屏闪动的情况,因为此时页面DOM结构已经生成。因此建议将对无依赖的请求放到create中
3.3 Vue中,有哪两个钩子会执行多次
beforeUpdate 和 update。因为只要data中的数据发生变化,就会触发这两个钩子执行
3.4 Vue中,哪些钩子只会执行1次?
beforeCreate、created和beforeMount、mounted
3.5 完整的父子组件生命周期
-
渲染过程:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
-
子组件更新过程:
- 影响到父组件:父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
- 不影响父组件:子beforeUpdate ->子updated
-
父组件更新过程:
- 影响到子组件:父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
- 不影响到子组件:父beforeUpdate -> 父updated
-
销毁过程:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
总结:父组件等待子组件完成后,才会执行自己对应完成的钩子
父子组件生命周期完整的执行顺序图:
3.6 Vue2 和 Vue3 的生命周期有什么区别?
- Vue3 的生命周期函数在使用前需要引入
- Vue3 中,
setup(),它是在beforeCreate和created之前运行的,所以你可以用它来代替这两个钩子 - Vue3 相比原有的生命周期,基本都是存在的,Vue3只不过有了新的命名:
beforeDestroy变成了beforeUnmounted;destroy变成了unmounted,名字变了但是原理还是没变的; - 新增了生命周期函数
onRenderTracked和onRenderTriggered-
onRenderTracked:调试钩子,每次触发页面重新渲染时自动执行。状态跟踪,他会跟踪页面上所有响应式变量和方法的状态,也就是我们return出去的值,只要页面有update的情况,他就会跟踪,然后生成一个event对象,我们可以通过event对象来查找程序所存在的问题。
特别注意,这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用
-
onRenderTriggered:调试钩子,当响应式依赖的变更触发了组件渲染时调用。状态触发,不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会明确的展示出来。
如果把
onRenderTracked是每个值都追踪,而onRenderTriggered是精准追踪,进行针对性调试特别注意,这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用
-