注意:本文档基于 Vue 2.x 版本编写。在 Vue 3 中,部分生命周期钩子名称已变更:
beforeDestroy→beforeUnmountdestroyed→unmountedVue 3 的生命周期请参考官方文档:https://cn.vuejs.org/guide/essentials/lifecycle.html
1.挂载阶段(初始化相关属性)
- beforeCreate
- created
- beforeMount
- mounted
执行顺序为:父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
一定得等子组件挂载完毕后,父组件才能挂在完毕,所以父组件的 mounted 在最后。
2.更新阶段(元素或组件的变更操作)
- beforeUpdate
- updated
注意:当父子组件有数据传递时,才有这个更新阶段执行顺序的比较。
执行顺序为:父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
3.销毁阶段(销毁相关属性)
- beforeDestroy
- destroyed
执行顺序为:父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
结合父子组件之后,一个完整的父子组件生命周期:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted->父beforeUpdate->子beforeUpdate->子updated->父updated->父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
4.总结
Vue 父子组件生命周期钩子的执行顺序遵循:从外到内,再从内到外。
上代码
<!-- html部分 -->
<div id="app">
<h1>app根组件</h1>
<hr />
<father></father>
</div>
<!-- 父组件 -->
<template id="father">
<div>
<h1>父组件</h1>
<button id="destroy" @click="btnDestroy">销毁组件</button>
<button id="update" @click="btnUpdate">更新组件</button>
<hr />
<child :msg="message"></child>
</div>
</template>
<!-- 子组件 -->
<template id="child">
<div>
<h1>子组件</h1>
<h3>{{msg}}</h3>
<h3>{{childMsg}}</h3>
</div>
</template>
// js部分
var child = {
template: "#child",
props: ["msg"],
data() {
return {
childMsg: "子组件自己的信息",
};
},
watch: {
msg: {
handler(newVal, oldVal) {
console.log("子组件————watch msg变化:", newVal, oldVal);
},
immediate: true, // 立即执行
},
childMsg: {
handler(newVal, oldVal) {
console.log("子组件————watch childMsg变化:", newVal, oldVal);
},
// 未设置immediate,不会立即执行
},
},
beforeCreate() {
console.log("子组件————beforeCreate...");
},
created() {
console.log("子组件————create...");
},
beforeMount() {
console.log("子组件————beforeMount...");
},
mounted() {
console.log("子组件————mounted...");
// 在mounted中修改childMsg,触发非immediate的watch
this.childMsg = "子组件自己的信息-修改后";
},
beforeUpdate() {
console.log("子组件————beforeUpdate...");
},
updated() {
console.log("子组件————updated...");
},
beforeDestroy() {
console.log("子组件————beforeDestroy...");
},
destroyed() {
console.log("子组件————destroyed...");
},
};
Vue.component("father", {
template: "#father",
data() {
return {
message: "来自father组件的信息",
};
},
components: {
child,
},
watch: {
message: {
handler(newVal, oldVal) {
console.log("父组件————watch message变化:", newVal, oldVal);
},
immediate: true, // 立即执行
},
},
beforeCreate() {
console.log("父组件————beforeCreate...");
},
created() {
console.log("父组件————create...");
},
beforeMount() {
console.log("父组件————beforeMount...");
},
mounted() {
console.log("父组件————mounted...");
},
beforeUpdate() {
console.log("父组件————beforeUpdate...");
},
updated() {
console.log("父组件————updated...");
},
beforeDestroy() {
console.log("父组件————beforeDestroy...");
},
destroyed() {
console.log("父组件————destroyed...");
},
methods: {
btnDestroy() {
//完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。
//触发 beforeDestroy 和 destroyed 的钩子。
// https://cn.vuejs.org/v2/api/#vm-destroy
this.$destroy();
console.log("销毁父子组件");
},
btnUpdate() {
this.message = "变更父组件的信息";
console.log(this.message);
},
},
});
var vm = new Vue({
el: "#app",
beforeCreate() {
console.log("app根组件————beforeCreate...");
},
created() {
console.log("app根组件————create...");
},
beforeMount() {
console.log("app根组件————beforeMount...");
},
mounted() {
console.log("app根组件————mounted...");
},
beforeUpdate() {
console.log("app根组件————beforeUpdate...");
},
updated() {
console.log("app根组件————updated...");
},
beforeDestroy() {
console.log("app根组件————beforeDestroy...");
},
destroyed() {
console.log("app根组件————destroyed...");
},
});

5.补充:
页面A到页面B跳转的时候,发生了什么?
首先是先B组件先created然后beforeMount接着A组件才被销毁,A组件才执行beforeDestory,以及destoryed,最后B组件才开始mounted
即:
B页面created>B页面beforeMount>A页面beforeDestory>A页面destoryed>B页面mounted
5.1 watch执行时机
官网的生命周期图中, init reactivity 是晚于 beforeCreate 但是早于 created 的。watch 加了 immediate: true,应当同 init reactivity 周期一同执行,会早于 created 执行。
而正常的 watch 执行,则是 mounted 周期后触发 data changes 的周期执行,晚于 created 执行。
当 watch 设置 immediate:true 的情况下watch 先执行,mounted 后执行
代码示例说明
在上面的代码示例中,我们添加了以下watch配置:
- 父组件:添加了对
message属性的watch,设置了immediate: true - 子组件:
- 添加了对
msg属性的watch,设置了immediate: true - 添加了对
childMsg属性的watch,未设置immediate - 在
mounted钩子中修改了childMsg的值,以触发非immediate的watch
- 添加了对
执行顺序会是:
- 父组件beforeCreate → 父组件watch message(immediate: true) → 父组件created → 父组件beforeMount → 子组件beforeCreate → 子组件watch msg(immediate: true) → 子组件created → 子组件beforeMount → 子组件mounted → 子组件修改childMsg → 子组件beforeUpdate → 子组件watch childMsg → 子组件updated → 父组件mounted
这样可以清晰地看到:
- 带有
immediate: true的watch会在created之前执行 - 不带
immediate的watch会在数据变化时执行,晚于mounted
