Vue 3 与 Vue 2 的生命周期有很多相似之处,但也有明显的变化。Vue 3 对生命周期钩子做了重命名和优化,使得生命周期更加灵活,特别是在组合式 API 中。以下是 Vue 3 和 Vue 2 的生命周期对比、使用时机、以及常见使用场景。
Vue 2 生命周期
在 Vue 2 中,生命周期钩子如下:
beforeCreate
:实例刚创建时调用,数据和事件还未初始化。created
:实例创建完成,数据和事件已完成初始化,但尚未挂载到 DOM 上。beforeMount
:模板已经编译,挂载前调用,DOM 还未渲染。mounted
:实例挂载完成,模板编译生成的 DOM 已插入页面。beforeUpdate
:响应式数据更新时触发,DOM 尚未更新。updated
:组件 DOM 更新完成后调用。activated
:<keep-alive> 组件激活时调用。deactivated
:<keep-alive> 组件停用时调用。beforeDestroy
:组件销毁前调用。destroyed
:组件销毁完成。
Vue 3 生命周期
Vue 3 的生命周期与 Vue 2 类似,但重命名了一些钩子以适应组合式 API。以下是 Vue 3 的生命周期钩子:
setup
:组合式 API 的初始化阶段,用于创建响应式数据、定义方法等。onBeforeMount
(相当于 Vue 2 的beforeMount
):DOM 未挂载。onMounted
(相当于 Vue 2 的mounted
):DOM 已挂载。onBeforeUpdate
(相当于 Vue 2 的beforeUpdate
):数据更新,DOM 未更新。onUpdated
(相当于 Vue 2 的updated
):数据更新后 DOM 已更新。onBeforeUnmount
(相当于 Vue 2 的beforeDestroy
):组件销毁前。onUnmounted
(相当于 Vue 2 的destroyed
):组件销毁后。onActivated
:<keep-alive> 组件激活。onDeactivated
:<keep-alive> 组件停用。
此外,Vue 3 引入了一些新的生命周期钩子函数,提供更灵活的控制:
onRenderTracked
:用于追踪组件的渲染依赖。onRenderTriggered
:当组件重新渲染时触发,调试渲染性能非常有用。
使用时机与场景
1. 数据初始化:created
(Vue 2) / setup
(Vue 3)
- Vue 2:
created
阶段用于初始化数据、调用 API 等操作。 - Vue 3:在组合式 API 中使用
setup
,可以直接定义ref
或reactive
变量,同时可以进行异步操作,如调用 API 获取数据。
示例:
// Vue 2
created() {
this.fetchData();
}
// Vue 3
<script setup>
import { ref, onMounted } from 'vue';
const data = ref(null);
async function fetchData() {
const response = await fetch('https://api.example.com/data');
data.value = await response.json();
}
fetchData();
</script>
2. DOM 操作:mounted
mounted
钩子在 Vue 2 和 Vue 3 中都有,但 Vue 3 中的组合式 API 使用 onMounted
。
- Vue 2:可以在
mounted
中直接获取 DOM 节点。 - Vue 3:通过
onMounted
钩子进行 DOM 操作,适合对渲染后的 DOM 进行操作。
示例:
// Vue 2
mounted() {
this.$refs.myElement.focus();
}
// Vue 3
<script setup>
import { onMounted, ref } from 'vue';
const myElement = ref(null);
onMounted(() => {
myElement.value.focus();
});
</script>
<template>
<input ref="myElement" />
</template>
3. 组件更新:updated
和 beforeUpdate
- Vue 2:
beforeUpdate
和updated
钩子分别在更新前和更新后触发,适用于需要监听和处理数据变化的情况。 - Vue 3:通过
onBeforeUpdate
和onUpdated
实现类似效果。
示例:
// Vue 2
beforeUpdate() {
console.log('组件即将更新');
},
updated() {
console.log('组件已更新');
}
// Vue 3
import { onBeforeUpdate, onUpdated } from 'vue';
onBeforeUpdate(() => {
console.log('组件即将更新');
});
onUpdated(() => {
console.log('组件已更新');
});
4. 组件销毁:beforeDestroy
和 destroyed
(Vue 2) / onBeforeUnmount
和 onUnmounted
(Vue 3)
- Vue 2:在
beforeDestroy
中可以做一些清理工作,比如移除事件监听器或销毁定时器。 - Vue 3:
onBeforeUnmount
和onUnmounted
用于相同场景,且支持组合式 API 的写法。
示例:
// Vue 2
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
},
destroyed() {
console.log('组件已销毁');
}
// Vue 3
import { onBeforeUnmount, onUnmounted } from 'vue';
function handleResize() {
console.log('窗口大小变化');
}
window.addEventListener('resize', handleResize);
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
});
onUnmounted(() => {
console.log('组件已销毁');
});
5. 依赖追踪:onRenderTracked
和 onRenderTriggered
(Vue 3 特有)
Vue 3 新增的 onRenderTracked
和 onRenderTriggered
,适合在调试中使用,帮助开发者了解组件渲染的依赖关系,找出潜在性能问题。
示例:
import { onRenderTracked, onRenderTriggered } from 'vue';
onRenderTracked((e) => {
console.log('依赖追踪:', e);
});
onRenderTriggered((e) => {
console.log('触发渲染:', e);
});
Vue 3 和 Vue 2 生命周期钩子的总结对比
功能 | Vue 2 生命周期 | Vue 3 生命周期(组合式 API) | 使用场景 |
---|---|---|---|
数据初始化 | created | setup | 初始化数据、调用 API |
初次渲染 | beforeMount / mounted | onBeforeMount / onMounted | DOM 操作、动画 |
数据更新 | beforeUpdate / updated | onBeforeUpdate / onUpdated | 监听和响应数据变化 |
组件销毁 | beforeDestroy / destroyed | onBeforeUnmount / onUnmounted | 清理定时器、事件监听 |
依赖追踪 | 不适用 | onRenderTracked / onRenderTriggered | 调试性能问题 |
在 Vue 3 中,组合式 API 带来了更高的灵活性,支持更加简洁的生命周期钩子函数,同时还允许在 setup
阶段完成更多初始化工作。
在 Vue 中,父子组件的生命周期钩子执行顺序在组件创建、更新、销毁的过程中有不同的执行方式。了解父子组件的生命周期钩子执行顺序有助于在复杂组件间的状态传递、事件监听等操作中更好地控制和优化代码。
父子组件生命周期钩子执行顺序
以下是 Vue 3 和 Vue 2 中父子组件的生命周期钩子执行顺序的对比说明。
1. 组件的创建过程
在组件创建时,Vue 3 和 Vue 2 的父子组件生命周期钩子的执行顺序是相同的,遵循“父 beforeCreate -> 子 beforeCreate -> 子 created -> 父 created”的方式。详细执行顺序如下:
- 父组件的
beforeCreate
:父组件实例刚创建,数据和事件尚未初始化。 - 父组件的
created
:父组件实例已创建完成,数据和事件初始化完成。 - 子组件的
beforeCreate
:子组件实例创建。 - 子组件的
created
:子组件初始化完成。 - 子组件的
beforeMount
:模板编译完成,但 DOM 未挂载。 - 子组件的
mounted
:子组件完成挂载,DOM 插入页面。 - 父组件的
beforeMount
:父组件模板编译完成,准备挂载。 - 父组件的
mounted
:父组件挂载完成,整个组件树的初次渲染完成。
总结执行顺序:
- 父
beforeCreate
-> 父created
- 子
beforeCreate
-> 子created
-> 子beforeMount
-> 子mounted
- 父
beforeMount
-> 父mounted
示例代码:
<!-- ParentComponent.vue -->
<template>
<div>
<p>Parent Component</p>
<ChildComponent />
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
onBeforeMount(() => console.log('Parent beforeMount'));
onMounted(() => console.log('Parent mounted'));
</script>
<!-- ChildComponent.vue -->
<template>
<p>Child Component</p>
</template>
<script setup>
onBeforeMount(() => console.log('Child beforeMount'));
onMounted(() => console.log('Child mounted'));
</script>
输出顺序:
Parent beforeCreate
Parent created
Child beforeCreate
Child created
Child beforeMount
Child mounted
Parent beforeMount
Parent mounted
2. 组件更新过程
在组件更新过程中,由于子组件的变化会影响父组件,所以更新顺序从“父 beforeUpdate
”开始。
- 父组件的
beforeUpdate
:父组件的响应式数据更新后,准备重新渲染。 - 子组件的
beforeUpdate
:子组件的响应式数据更新,准备重新渲染。 - 子组件的
updated
:子组件更新完成,新的 DOM 已插入。 - 父组件的
updated
:父组件更新完成。
总结执行顺序:
- 父
beforeUpdate
-> 子beforeUpdate
-> 子updated
-> 父updated
示例代码:
在以下示例中,父组件中的 counter
变化会触发父子组件的更新。
<!-- ParentComponent.vue -->
<template>
<div>
<p>Parent Component: {{ counter }}</p>
<button @click="increment">Increment</button>
<ChildComponent :counter="counter" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const counter = ref(0);
const increment = () => counter.value++;
onBeforeUpdate(() => console.log('Parent beforeUpdate'));
onUpdated(() => console.log('Parent updated'));
</script>
<!-- ChildComponent.vue -->
<template>
<p>Child Component: {{ counter }}</p>
</template>
<script setup>
import { toRef } from 'vue';
const props = defineProps({ counter: Number });
onBeforeUpdate(() => console.log('Child beforeUpdate'));
onUpdated(() => console.log('Child updated'));
</script>
输出顺序(点击按钮后):
Parent beforeUpdate
Child beforeUpdate
Child updated
Parent updated
3. 组件销毁过程
当父组件或子组件被销毁时,它们的生命周期钩子执行顺序为“父 beforeUnmount
-> 子 beforeUnmount
-> 子 unmounted
-> 父 unmounted
”。
- 父组件的
beforeUnmount
:父组件销毁前触发。 - 子组件的
beforeUnmount
:子组件销毁前触发。 - 子组件的
unmounted
:子组件销毁完成。 - 父组件的
unmounted
:父组件销毁完成。
总结执行顺序:
- 父
beforeUnmount
-> 子beforeUnmount
-> 子unmounted
-> 父unmounted
示例代码:
在以下示例中,点击按钮销毁子组件。
<!-- ParentComponent.vue -->
<template>
<div>
<p>Parent Component</p>
<button @click="toggleChild">Toggle Child</button>
<ChildComponent v-if="showChild" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const showChild = ref(true);
const toggleChild = () => showChild.value = !showChild.value;
onBeforeUnmount(() => console.log('Parent beforeUnmount'));
onUnmounted(() => console.log('Parent unmounted'));
</script>
<!-- ChildComponent.vue -->
<template>
<p>Child Component</p>
</template>
<script setup>
onBeforeUnmount(() => console.log('Child beforeUnmount'));
onUnmounted(() => console.log('Child unmounted'));
</script>
输出顺序(销毁子组件后):
Parent beforeUnmount
Child beforeUnmount
Child unmounted
Parent unmounted
总结
生命周期阶段 | Vue 2 执行顺序 | Vue 3 执行顺序(组合式 API) |
---|---|---|
创建过程 | 父 beforeCreate -> 父 created -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 beforeMount -> 父 mounted | 相同 |
更新过程 | 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated | 相同 |
销毁过程 | 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed | 父 beforeUnmount -> 子 beforeUnmount -> 子 unmounted -> 父 unmounted |
- Vue 3 在销毁阶段,重命名了销毁相关的生命周期钩子为
onBeforeUnmount
和onUnmounted
,并支持组合式 API。 - 父子组件的生命周期顺序在组件创建、更新和销毁阶段的钩子触发顺序在 Vue 3 和 Vue 2 中是基本一致的。