详解 Vue2 组件生命周期
详解 Vue2 组件生命周期
概述
在 Vue 中,一个组件本质上是一个拥有预定义选项的 Vue 实例对象,而组件生命周期(Life Cycle),就是指一个 Vue 实例被创建、运行、销毁的整个阶段
生命周期函数
也称为生命周期钩子,是 Vue 提供的内置函数,会伴随着 Vue 实例的生命周期,自动按次序执行,强调的是一个时间点
函数种类
每个 Vue 实例在被创建时都要经过一系列的初始化过程,例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等
与此同时,Vue 会在 Vue 实例创建、运行、销毁各阶段执行不同的生命周期钩子,使得开发者可在不同阶段针对需求调用不同的生命周期钩子
Vue2 组件的生命周期中,可调用的 8 个生命周期钩子:

函数使用
在 Vue2 中,生命周期钩子是直接作为选项被调用,即与 data
选项平级,函数内部的 this
指向调用它的 Vue 实例/组件实例
<script>
export default {
created: function () {
// this指向当前组件实例
},
// ES6对象方法简写形式
created() {
// this指向当前组件实例
}
}
</script>
Tips
无论开发者是否有调用,所有生命周期钩子都会按组件生命周期的顺序自动被执行
生命周期钩子,或所有函数形式的选项式 API,不能使用箭头函数,因为它内部没有
this
对象,若在箭头函数中使用this
,它将作为变量一直向上级词法作用域查找直至找到为止,否则可能会报无法读取 undefined 的属性
等错误Vue2 还提供了 4 个与生命周期相关的实例方法,参考 Vue2 官方 API
详解生命周期
在了解完生命周期钩子后,接下来将以一个组件实例的创建、运行、销毁的过程(在内存中很快完成),详细分析 Vue2 的 Vue 实例生命周期(一个组件实例本质上是一个拥有预定义选项的 Vue 实例)
Tips
生命周期图示类似于程序流程图,其中箭头表示控制流,矩形表示加工步骤(起始框、执行框),菱形表示逻辑条件(判断框)
一、组件创建阶段
1. new Vue()
该步骤旨在创建一个 Vue 实例,在不同情况下,创建 Vue 实例有着不同的方法:
在
Vue.js
最基础的用法中,是直接在 HTML 文件中,通过new
关键字来调用Vue.js
提供的 Vue 构造函数以创建 Vue 实例,然后使用 Vue 提供的选项式 API
来协助渲染当前 HTML 文件的结构、行为、样式
此用法并未涉及到组件系统,但本质上已经在使用组件来定义页面 UI 结构,组件在该用法中是通过包含 Vue选项式 API
的JavaScript 对象
来定义的,并未使用.vue
文件在 Vue 项目或使用构建工具中,则是使用
.vue
文件来定义组件
Vue 项目接入组件系统:在main.js
中创建 Vue 实例并设置 DOM 挂载点后,通过渲染函数解析.vue
文件:- 将页面结构交由组件
template
标签定义 - 页面行为交由组件
script
标签定义 - 页面样式由组件
style
标签定义
通过组件嵌套进一步完善页面的 UI 结构,此时原本的 HTML 文件更像是组件系统的出口文件,而根组件则是其他组件的入口文件
- 将页面结构交由组件
.vue
文件可近似理解为构造函数,在通过标签形式使用组件时,相当于 new
构造函数以创建一个组件实例
2. Init Events & Lifecycle
在创建出 Vue 实例后,Vue 就会在内存中初始化此组件实例的事件以及生命周期函数
3. beforeCreate
当上一步事件与生命周期函数初始化完成后,beforeCreate
函数就会被自动执行
阶段状态
此阶段组件实例的 props/data/methods
都尚未创建,处于不可用状态,因此 beforeCreate
函数在实际开发中用处不大
4. Init Injections & Reactivity
beforeCreate
函数执行完毕后,开始初始化组件实例的 props/data/methods
5. created
当上一步组件实例的注入与校验初始化完成后,created
函数就会被自动执行
阶段状态
- 组件实例的
props/data/methods
均已创建好,处于可用状态 - 组件实例的模板结构
template
尚未生成 created
函数十分重要,它是生命周期中最早能发起 Ajax 请求的函数
6. 编译 HTML 结构
created
函数执行完毕后,则需要开始编译 HTML 结构,需按顺序进行一系列的条件判断:
(1)判断 el
选项是否存在:
存在:即 Vue 实例设置了
el
选项,则直接进入下一步:判断template
选项是否存在
不存在:则等待 Vue 实例 调用$mount()
方法后,再进入template
选项判断框,否则将报错
(2)判断 template
选项是否存在:
存在:将
template
选项定义的模板结构,编译到render
函数中传入的参数所控制的区域
不存在:Vue 会根据组件实例中的template
部分编译el
选项所控制区域的 HTML 结构,此 HTML 结构可称为outerHTML
outerHTML
表示外层 HTML,是因为所编译的 HTML 来源于组件的 template
,而不是 el
选项所控制区域内部本身的 HTML 结构
(3)开始编译
当执行完上两步的判断后,开始基于数据和模板,在内存中编译生成页面的 HTML 结构,编译的工作由依赖包中的 vue-template-compiler
完成
7. beforeMount
当页面 HTML 结构编译完成后,beforeMount
函数就会被自动执行
阶段状态
- 内存中已编译好 HTML 结构,但未渲染到浏览器中,此时浏览器中还没有当前组件的 DOM 结构
- 此生命周期钩子同样可以发起 Ajax 请求,但在
created
函数中能更早地拿到数据,因此它在实际开发中用处不大
8. 创建 vm.$el 并替换 el 选项
当 beforeMount
函数执行完毕后,紧接着:
(1)用内存中编译生成的 HTML 结构,替换掉 el
选项指定的 DOM 元素
(2)同时创建 Vue 实例属性 vm.$el
,表示 Vue 实例使用的根 DOM 元素
阶段状态
此执行框结束后,组件中的 DOM 结构就已经被渲染到浏览器中
9. mounted
当 el
选项指定的 DOM 被组件模板结构替换且 vm.$el
创建后,mounted
函数就会被自动执行
阶段状态
此时浏览器已包含了当前组件的 DOM 结构,该生命周期钩子是最早可操作到组件中的 DOM 元素的,在实际开发中十分重要
10. Mounted
进入 Mounted 阶段,表示组件实例已挂载完毕,已成功创建并渲染到浏览器中
小结:组件创建阶段图解

二、组件运行阶段
组件在内存中的创建阶段结束后,就进入组件的运行阶段:
1. beforeUpdate
当组件实例中的任何数据(如 data
选项、computed
选项)发生变化时,beforeUpdate
函数就会被自动执行
阶段状态
此阶段的数据已被更新,但相应的 DOM 结构未重新渲染
2. 重新渲染虚拟 DOM
当 beforeUpdate
生命周期钩子执行完毕后,将根据最新的数据,重新渲染组件的虚拟 DOM,并将更新应用到真实的 DOM 中
3. updated
当 DOM 重新渲染完毕后,updated
函数就会被自动执行
此阶段表示 Vue 已根据最新的数据,完成了组件 DOM 结构的重新渲染
操作最新 DOM
当数据变化后,为了能够操作到最新的 DOM 结构,将逻辑代码写到 updated
函数虽是可行的,但该生命周期钩子会在每次数据变化时都会被执行一次
作为补充,Vue 提供了实例方法 vm.$nextTick()
,它表示将在 DOM 更新完毕后调用回调,参考 vm.$nextTick
4. Mounted
更新完毕后再次进入 Mounted
阶段,等待下一次数据更新或进行销毁
小结:
整个重渲染过程最少执行 0 次,即数据一直没有发生任何变化,最多执行无限次
组件运行阶段图解:

三、组件销毁阶段
当调用了实例方法 vm.$destroy()
方法后,将进入组件销毁阶段:
1. beforeDestroy
调用实例方法 vm.$destroy()
后,beforeDestroy
函数就会被自动执行,此时尚未销毁组件,组件还处于正常工作状态
2. 销毁组件
当 beforeDestroy
函数执行完毕后,将真正进入组件销毁阶段:
销毁组件的侦听器,子组件以及事件监听函数
3. Destroyed
此阶段表示组件已被销毁,此组件在浏览器中对应的 DOM 结构已被完全移除
4. destroyed
当组件完全销毁后,destroyed
函数就会被自动执行
小结:组件销毁阶段图解

四、完整图解

总结
生命周期强调的是时间段,生命周期函数强调的是时间点
整个生命周期中,最重要的是 created
、mounted
、updated
3 个函数