Appearance
生命周期
TIP
本小节对应的项目源代码,可以去 刘龙彬/vue3-component-study-2 仓库中下载。
Vue 项目在运行的时候,每个 SFC 组件都会经历一个创建 -> 挂载 -> 更新 -> 销毁的过程。这个过程称为组件的生命周期。一个 SFC 组件完整的生命周期过程如下图所示(共分为 4 个阶段)。
在每个生命周期阶段中,Vue 会自动按顺序执行一系列内置的函数,这些伴随着生命周期执行的函数叫做“生命周期函数(钩子)”:

组件创建阶段
组件创建阶段的主要任务是:初始化 setup 函数和初始化选项式 API。
setup
在组件的创建阶段,会先执行 setup()
函数。setup
函数是组合式 API 的入口:
vue
<script>
export default {
// 组合式 API 的入口
setup() {},
// 选项式 API
data() {},
methods: {}
}
</script>
<template></template>
<style></style>
而 <script setup>
是 setup()
函数的简写形式:
vue
<script setup>
// 此处,仅支持“组合式 API”的调用,不支持“选项式 API”
</script>
<template></template>
<style></style>
TIP
setup 不是生命周期函数,它只是 Vue3 提供的组合式 API 的入口。
beforeCreate
beforeCreate 是组件创建阶段的第 1 个生命周期函数。在 beforeCreate 生命周期函数被执行的时候,SFC 组件在内存中还没有创建完成,此时选项式 API 也没有被初始化,因此在此生命周期函数中无法访问选项式 API:
vue
<script>
export default {
setup() {
console.log('--setup--')
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
// 在 beforeCreate 中无法访问选项式 API 中定义的数据、方法、计算属性等,因为他们还没有被初始化
console.log(this.num) // 输出:undefined
this.showNumber() // 报错:Uncaught TypeError: this.showNumber is not a function
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
}
}
}
</script>
<template>
<div>
<h1>SFC 组件的生命周期</h1>
</div>
</template>
created
created 是组件创建阶段的第 2 个生命周期函数。在 created 生命周期函数执行的时候,Vue 的组件渲染器已经完成了对当前组件的选项式 API 的初始化。因此,在 created 中可以访问到组件上声明的选项式 API 的数据、方法、计算属性等:
vue
<script>
export default {
setup() {
console.log('--setup--')
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
// 输出:0
console.log(this.num)
// 输出:
// data 中 num 的值是:0
// 计算属性 numPlus2 的值是:0
this.showNumber()
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1>SFC 组件的生命周期</h1>
</div>
</template>
TIP
当 created 函数执行完毕之后,组件创建阶段的生命周期函数就执行完毕了,组件会自动进入到挂载阶段并执行挂载阶段的生命周期函数。
组件挂载阶段
组件挂载阶段的主要任务是:编译 <template>
中的模板内容并把组件渲染到浏览器中。
预编译模板 & 即时编译模板
TIP
预编译模板:通过构建工具对 SFC 组件进行预构建之后,得到的就是预编译的模板。在浏览器中仅需要 Runtime 即可渲染组件结构。
即时编译模板:没有通过构建工具对 SFC 进行预构建,而是在浏览器中先调用 Compiler 进行即时编译,然后再通过 Runtime 渲染组件模板。
在刚进入组件的挂载阶段时,Vue 会先判断当前组件中是否存在预编译的模板,如果存在,则直接把预编译模板交给 Runtime 进行渲染。否则会先调用 Compiler 编译模板,在调用 Runtime 渲染。
beforeMount
beforeMount 是组件挂载阶段的第 1 个生命周期函数。此时仅仅把组件的模板编译成了内存中的虚拟 DOM,但是还没有把虚拟 DOM 渲染为浏览器中真实的 DOM 节点。因此在 beforeMount 中无法获取组件中的 DOM 元素:
vue
<script>
export default {
setup() {
console.log('--setup--')
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 运行阶段
beforeMount() {
console.log('--beforeMount--')
// 在 beforeMount 中无法获取当前组件的真实 DOM,因为此时尚未渲染真实 DOM
const titleDOM = document.querySelector('.title')
console.log(titleDOM) // 输出:null
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
</div>
</template>
在组合式 API 中可以使用 onBeforeMount(fn)
API 来替代选项式 API 中的 beforeMount
函数:
vue
<script>
// 导入选项式 API
import { onBeforeMount } from 'vue'
export default {
setup() {
console.log('--setup--')
// 在 beforeMount 阶段执行 fn 函数
onBeforeMount(() => {
console.log('--组合式 API:onBeforeMount--')
// 在 beforeMount 中无法获取当前组件的真实 DOM,因为此时尚未渲染真实 DOM
const titleDOM = document.querySelector('.title')
console.log(titleDOM) // 输出:null
})
},
beforeMount() {
console.log('--beforeMount--')
// 在 beforeMount 中无法获取当前组件的真实 DOM,因为此时尚未渲染真实 DOM
const titleDOM = document.querySelector('.title')
console.log(titleDOM) // 输出:null
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
</div>
</template>
mounted
mounted 是组件挂载阶段的第 2 个生命周期函数。此时组件的模板已经完成了首次挂载,浏览器的页面中已存在当前组件的真实 DOM。很多依赖于 DOM 元素的第三方插件的初始化工作,都需要在 mounted 函数中执行(例如:把 div 初始化为 echarts 的图表容器):
vue
<script>
import { onBeforeMount } from 'vue'
import * as echarts from 'echarts'
export default {
setup() {
console.log('--setup--')
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
// 可以获取到真实的 DOM 元素
const dom = document.querySelector('#main')
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(dom)
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
})
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<!-- 图表容器 -->
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
与之对应的,在组合式 API 中可以使用 onMounted
API 来替代选项式 API 中的 mounted
函数:
vue
<script>
import { onBeforeMount, onMounted } from 'vue'
import * as echarts from 'echarts'
export default {
setup() {
console.log('--setup--')
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => {
console.log('--组合式 API:onMounted--')
// 可以获取到真实的 DOM 元素
const dom = document.querySelector('#main')
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(dom)
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
})
})
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
组件更新阶段
组件更新阶段的主要任务是:根据数据的变化,更新并重新渲染组件的 DOM 结构。
beforeUpdate
当组件中的响应式数据(data、computed、props)发生变化之后,会先执行更新阶段的 beforeUpdate
生命周期函数。
此时组件中的数据是新的,但组件的 DOM 结构尚未被重新渲染,因此无法获取到更新后最新的 DOM 元素。
vue
<script>
import { onBeforeMount, onMounted } from 'vue'
import * as echarts from 'echarts'
export default {
setup() {
console.log('--setup--')
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
const dom = document.querySelector('.num')
console.log(`当前的数据是:${this.num},DOM 中的文本内容是:${dom.textContent}`)
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
与之对应的,在组合式 API 中可以使用 onBeforeUpdate
API 来替代选项式 API 中的 beforeUpdate
函数:
vue
<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate } from 'vue'
export default {
setup() {
console.log('--setup--')
const count = ref(0)
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
onBeforeUpdate(() => {
console.log('--组合式 API:onBeforeUpdate--')
const dom = document.querySelector('.count')
console.log(`当前的数据是:${count.value},DOM 中的文本内容是:${dom.textContent}`)
})
return {
count
}
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<p class="count" @click="count++">count 的值是:{{ count }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
updated
updated 是更新阶段的第 2 个生命周期函数。此时组件已经完成了 DOM 的更新渲染。因此在 updated 中获取到的数据和 DOM 都是最新的。
vue
<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate } from 'vue'
export default {
setup() {
console.log('--setup--')
const count = ref(0)
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
onBeforeUpdate(() => console.log('--组合式 API:onBeforeUpdate--'))
return {
count
}
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
},
updated() {
console.log('--updated--')
const dom = document.querySelector('.num')
console.log(`当前的数据是:${this.num},DOM 中的文本内容是:${dom.textContent}`)
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<p class="count" @click="count++">count 的值是:{{ count }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
与之对应的,在组合式 API 中可以使用 onUpdated
API 来替代选项式 API 中的 updated
函数:
vue
<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
console.log('--setup--')
const count = ref(0)
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
onBeforeUpdate(() => console.log('--组合式 API:onBeforeUpdate--'))
onUpdated(() => {
console.log('--组合式 API:onUpdated--')
const dom = document.querySelector('.count')
console.log(`当前的数据是:${count.value},DOM 中的文本内容是:${dom.textContent}`)
})
return {
count
}
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
},
updated() {
console.log('--updated--')
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<p class="count" @click="count++">count 的值是:{{ count }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
触发次数
组件更新阶段的生命周期函数,至少执行 0 次,最多执行 N 次:
- 如果组件挂载之后,数据从未发生变化,则更新阶段的生命周期函数执行 0 次;
- 如果组件的数据变化了 N 次,则更新阶段的生命周期函数会执行 N 次;
组件销毁阶段
组件销毁阶段的主要任务是:在组件销毁时手动清理一些副作用,例如:计时器、DOM 事件监听器或者与服务器的连接。
beforeUnmount 和 unmounted
beforeUnmount 是销毁阶段的第 1 个生命周期函数,它在组件实例被卸载之前调用,此时组件实例依然还保有全部的功能。
unmounted 是销毁阶段的第 2 个生命周期函数,它在组件实例被卸载之后调用,此时:
- 其所有子组件都已经被卸载;
- 所有相关的响应式作用 (渲染作用以及
setup()
时创建的计算属性和侦听器) 都已经停止,DOM 元素不可用;
vue
<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
console.log('--setup--')
const count = ref(0)
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
onBeforeUpdate(() => console.log('--组合式 API:onBeforeUpdate--'))
onUpdated(() => console.log('--组合式 API:onUpdated--'))
return {
count
}
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
},
updated() {
console.log('--updated--')
},
// 销毁阶段
beforeUnmount() {
console.log('--beforeUnmount--')
const dom = document.querySelector('.count')
console.log(`当前的数据是:${this.count},DOM 中的文本内容是:${dom.textContent}`)
},
unmounted() {
console.log('--unmounted--')
// 下面的代码会报错,因为 DOM 已经卸载
// const dom = document.querySelector('.count')
// console.log(`当前的数据是:${this.count},DOM 中的文本内容是:${dom.textContent}`)
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<p class="count" @click="count++">count 的值是:{{ count }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
与之对应的,在组合式 API 中可以使用 onBeforeUnmount
和 onUnmounted
API 来替代选项式 API 中的 beforeUnmount
和 unmounted
函数:
vue
<script>
import { ref, computed, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
export default {
setup() {
console.log('--setup--')
const count = ref(0)
const countPlus2 = computed(() => count.value * 2)
const showCount = () => {
console.log('count 的值是:' + count.value)
console.log('计算属性 countPlus2 的值是:' + countPlus2.value)
}
onBeforeMount(() => console.log('--组合式 API:onBeforeMount--'))
onMounted(() => console.log('--组合式 API:onMounted--'))
onBeforeUpdate(() => console.log('--组合式 API:onBeforeUpdate--'))
onUpdated(() => console.log('--组合式 API:onUpdated--'))
// 组件销毁阶段的生命周期函数
onBeforeUnmount(() => {
console.log('--组合式 API:onBeforeUnmount--')
const dom = document.querySelector('.count')
console.log(`当前的数据是:${count.value},DOM 中的文本内容是:${dom.textContent}`)
})
onUnmounted(() => {
console.log('--组合式 API:onUnmounted--')
// 下面的代码会报错,因为 DOM 已经卸载
// const dom = document.querySelector('.count')
// console.log(`当前的数据是:${count.value},DOM 中的文本内容是:${dom.textContent}`)
})
return {
count
}
},
// 创建阶段
beforeCreate() {
console.log('--beforeCreate--')
},
created() {
console.log('--created--')
},
// 挂载阶段
beforeMount() {
console.log('--beforeMount--')
},
mounted() {
console.log('--mounted--')
},
// 更新阶段
beforeUpdate() {
console.log('--beforeUpdate--')
},
updated() {
console.log('--updated--')
},
// 销毁阶段
beforeUnmount() {
console.log('--beforeUnmount--')
},
unmounted() {
console.log('--unmounted--')
},
// 选项式 API 的数据
data() {
return {
num: 0
}
},
// 选项式 API 的方法
methods: {
showNumber() {
console.log('data 中 num 的值是:' + this.num)
console.log('计算属性 numPlus2 的值是:' + this.numPlus2)
}
},
// 选项式 API 的计算属性
computed: {
numPlus2() {
return this.num * 2
}
}
}
</script>
<template>
<div>
<h1 class="title">SFC 组件的生命周期</h1>
<p class="num" @click="num++">num 的值是:{{ num }}</p>
<p class="count" @click="count++">count 的值是:{{ count }}</p>
<div id="main" style="width: 600px; height: 400px"></div>
</div>
</template>
onBeforeUnmount 的用法示例
在 onMounted 中开启的定时器,需要在 onBeforeUnmount 中手动清除。否则当组件被卸载后,定时器也会继续执行:
vue
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
const count = ref(0)
let timerId = null
// 组件挂载完成后,开启定时器
onMounted(() => {
timerId = setInterval(() => {
count.value++
console.log('触发了定时器')
}, 1000)
})
// 当组件即将卸载,手动清理定时器
onBeforeUnmount(() => {
clearInterval(timerId)
timerId = null
})
</script>
<template>
<h1>count 的值是:{{ count }}</h1>
</template>
嵌套组件的生命周期函数的执行顺序
假设有 Level1、Level2、Level3 三个组件相互嵌套。其中 Level1 是父组件,Level2 是子组件,Level3 是孙组件。
在组件创建阶段,这三个组件的生命周期函数的执行顺序分别是:
# 根据嵌套顺序,先依次执行父组件的 onBeforeMount
level-1 onBeforeMount
level-2 onBeforeMount
level-3 onBeforeMount
# 再从内向外,依次执行子组件的 onMounted
level-3 onMounted
level-2 onMounted
level-1 onMounted
在组件销毁阶段,这三个组件的生命周期函数的执行顺序分别是:
# 根据嵌套顺序,先依次执行父组件的 onBeforeUnmount
level-1 onBeforeUnmount
level-2 onBeforeUnmount
level-3 onBeforeUnmount
# 再从内向外,依次执行子组件的 onUnmounted
level-3 onUnmounted
level-2 onUnmounted
level-1 onUnmounted
在组件更新阶段,这三个组件互不影响,只会触发自己的 onBeforeUpdate
和 onUpdated
。
示例代码如下:
vue
<!-- App.vue -->
<script setup>
import { ref } from 'vue'
import Level1 from './components/Level1.vue'
const flag = ref(true)
</script>
<template>
<button @click="flag = !flag">Toggle</button>
<hr />
<Level1 v-if="flag" />
</template>
vue
<!-- Level1.vue -->
<script setup>
import Level2 from './Level2.vue'
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, ref } from 'vue'
onBeforeMount(() => console.log('level-1 onBeforeMount'))
onMounted(() => console.log('level-1 onMounted'))
onBeforeUpdate(() => console.log('level-1 onBeforeUpdate'))
onUpdated(() => console.log('level-1 onUpdated'))
onBeforeUnmount(() => console.log('level-1 onBeforeUnmount'))
onUnmounted(() => console.log('level-1 onUnmounted'))
const c1 = ref(0)
</script>
<template>
<h1>Level-1 组件</h1>
<p @click="c1++">c1 的值:{{ c1 }}</p>
<hr />
<Level2 />
</template>
vue
<!-- Level2.vue -->
<script setup>
import Level3 from './Level3.vue'
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, ref } from 'vue'
onBeforeMount(() => console.log('level-2 onBeforeMount'))
onMounted(() => console.log('level-2 onMounted'))
onBeforeUpdate(() => console.log('level-2 onBeforeUpdate'))
onUpdated(() => console.log('level-2 onUpdated'))
onBeforeUnmount(() => console.log('level-2 onBeforeUnmount'))
onUnmounted(() => console.log('level-2 onUnmounted'))
const c2 = ref(0)
</script>
<template>
<h2>Level-2 组件</h2>
<p @click="c2++">c2 的值:{{ c2 }}</p>
<hr />
<Level3 />
</template>
vue
<!-- Level3.vue -->
<script setup>
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, ref } from 'vue'
onBeforeMount(() => console.log('level-3 onBeforeMount'))
onMounted(() => console.log('level-3 onMounted'))
onBeforeUpdate(() => console.log('level-3 onBeforeUpdate'))
onUpdated(() => console.log('level-3 onUpdated'))
onBeforeUnmount(() => console.log('level-3 onBeforeUnmount'))
onUnmounted(() => console.log('level-3 onUnmounted'))
const c3 = ref(0)
</script>
<template>
<h3>Level-3 组件</h3>
<p @click="c3++">c3 的值:{{ c3 }}</p>
</template>
总结
- 除了
beforeCreate
和created
之外,其它的选项式生命周期函数,都存在与之对应的组合式生命周期函数,即onXXX
。 - 若同时定义了选项式和组合式的生命周期函数,则组合式优先于选项式执行。
- 组件更新阶段的生命周期函数,会根据数据的变化执行 0 次或多次,而创建、挂载、销毁阶段的生命周期函数仅执行 1 次。
- 多个组件相互嵌套时,会根据组件嵌套的顺序,由外向内依次执行 onBeforeXXX 生命周期函数,再由内向外依次执行 onXXX 生命周期函数(仅适用于“挂载”和“销毁”阶段的生命周期函数)。