同步情况下
有如下结构代码:一个 form 父组件,两个 form-item 并列子组件,form-item 中各有一个 input 子组件。在每个组件的 beforeCreate、created、beforeMount 生命周期钩子中打印当前组件名称和钩子函数名称。结果如下:
<i-form :model="formValidate" :rules="ruleValidate">
<i-form-item label="用户名" prop="name">
<i-input v-model="formValidate.name"></i-input>
</i-form-item>
<i-form-item label="邮箱" prop="mail">
<i-input v-model="formValidate.mail"></i-input>
</i-form-item>
</i-form>
过程如下:在 mount 之前,是从外到内,依次执行 beforeCreate、created、beforeMount 方法,并列的两个子组件每个都先执行这三个方法。然后从内到外执行 mounted。Vue.js 的组件渲染顺序是由内而外的。
form beforeCreate
form created
form beforeMount
form-item beforeCreate
form-item created
form-item beforeMount
input beforeCreate
input created
input beforeMount
form-item beforeCreate
form-item created
form-item beforeMount
input beforeCreate
input created
input beforeMount
input mounted
form-item mounted
input mounted
form-item mounted
form mounted
结合源码看下规律
资料:《Vue 源码分析-组件化》:
beforeCreate 和 created 是在_init方法中调用,这个方法是先父后子调用。
beforeMount 是在调用 mountComponent 函数中,在执行 updateComponent 函数之前调用,也是先父后子。
mounted 方法是在组件的 insert 这个钩子函数上调用,是先子后父。
beforeUpdate 是先父后子,updated 是先子后父。
组件的销毁过程最终会调用 $destroy 方法,beforeDestory 在$destroy最开始执行,所以顺序是先父后子。
执行到vm.__patch__(vm._vnode, null)时触发子组件的的销毁钩子函数,递归调用,然后才会执行 destroyd 钩子函数,所以 destroyd 执行顺序是先子后父,和 mounted 过程一样。
规律:除了 beforeCreate 和 created 这一对是两个都是先父后子。其他的三对,beforeMount 和 mounted、beforeUpdate 和 updated、beforeDestory 和 destroyd 都是 beforeXXX 先父后子,XXXed 是先子后父。
生命周期函数为异步的情况
如下代码,created 是异步函数,此时会先调用 mounted :
export default {
methods: {
async asyncMethod() {
return Promise.resolve("asyncMethod");
},
},
async created() {
const data = await this.asyncMethod();
console.log("created", data); // 2. 后打印
},
mounted() {
console.log("mounted"); // 1. 先打印
},
};