前景提要:
1.有一对父子组件
2.父子组件中均有8个钩子函数
3.观察执行顺序及逻辑
先上结论,想看过程的可以继续看下面
结论:
当页面初次渲染时:
1.首先触发父组件的beforeCreate,created,beforeMount三个钩子
2.触发子组件的beforeCreate,created,beforeMount,mounted四个钩子
3.最后再触发父组件的挂载后mounted钩子
当页面更新时:
1.触发了子组件的更新前后beforeUpdate,updated两个钩子
当页面进行销毁时:
1.子组件进行销毁
触发自身的销毁前后beforeUpdate,updated两个钩子
2.父组件对子组件进行销毁时
首先触发父组件的更新前钩子beforeUpdate
然后触发子组件的销毁前后beforeDestroy和destroyed两个钩子
最后触发父组件的更新后updated钩子
知识点:
1.beforeCreate钩子
此时data el还未初始化 data,methods都还没有出现
2.created钩子
此时data中的数据项能拿到但是没有真实DOM,this.$data也可以拿到数据,methods也出现了
3.beforeMount 钩子
此时模板已经在内存中渲染好了,但还未渲染到页面
4.mounted钩子
此时将内存中渲染好的模板替换到浏览器中
5. beforeUpdate钩子
虚拟DOM重新渲染和打补丁之前被调用,在此修改data不会触发重渲染
6.updated钩子
虚拟DOM重新渲染 和打补丁之后被调用,此时不要修改data,否则会一直触发
beforeUpdate、updated这两个生命周期,进入死循环
7.beforeDestroy 钩子
此时实例准备进入销毁阶段,data methods 指令都还可以正常使用
8.destroyed 钩子
此时实例已经销毁,data methods 指令都不能使用
注意点:
全局变量的生命周期:生:页面加载时 死:页面关闭时
局部变量的生命周期:生:函数调用时 死:函数调用完毕时
参考代码(vue)
父:
<template>
<div>
<h1>hello</h1>
<MySon/>
</div>
</template>
<script>
import MySon from './MySon.vue'
export default {
components:{
MySon
},
beforeCreate () {
// 1. 创建前
console.log("beforeCreate --- 实例初始化前 父")
console.log(this.msg) // undefined
},
created () {
// 2. 创建后=> 发送ajax请求
console.log("created --- 实例初始化后 父")
console.log(this.msg) // "我是变量"
},
beforeMount () {
// 3. 挂载前
console.log("beforeMount --- vue的虚拟DOM, 挂载到真实的网页之前 父")
console.log(document.getElementById("myUl")) // null
// console.log(document.getElementById("myUl").children[1].innerHTML) // 报错
},
mounted () {
// 4. 挂载后=> 操作dom
console.log("mounted --- vue的虚拟DOM, 挂载到真实的网页上 父")
// console.log(document.getElementById("myUl").children[1].innerHTML)
console.log(document.querySelector('#myUl').children[1].innerText)
},
beforeUpdate () {
// 5. 更新前
console.log("beforeUpdate --- 数据更新, 页面更新前 父")
// 比如点击新增数组元素, vue会触发此生命周期函数, 但是此时页面并未更新, 所以获取不到新增的li标签
// console.log(document.getElementById("myUl").children[4].innerHTML) // 报错
},
updated () {
// 6. 更新后
console.log("updated --- 数据更新, 页面更新后 父")
console.log(document.getElementById("myUl").children[4].innerHTML)
},
beforeDestroy () {
// 7. 销毁前
// (清除定时器 / 解绑js定义的事件)
console.log("beforeDestroy --- 实例销毁之前调用 父")
},
destroyed () {
// 8. 销毁后
// (清除定时器 / 解绑js定义的事件)
console.log("destroyed --- 销毁完成 父")
},
}
</script>
<style>
</style>
子:
<template>
<div>
<ul id="myUl">
<li v-for="(item, ind) in arr" :key="ind">{{ item }}</li>
</ul>
<button
@click="arr.push(Math.random() * 10)"
>
增加一个元素
</button>
</div>
</template>
<script>
export default {
data () {
return {
msg: "我是变量",
arr: [1, 2, 3, 4],
isShow: true,
}
},
beforeCreate () {
// 1. 创建前
console.log("beforeCreate --- 实例初始化前")
console.log(this.msg) // undefined
},
created () {
// 2. 创建后=> 发送ajax请求
console.log("created --- 实例初始化后")
console.log(this.msg) // "我是变量"
// this.time = setInterval(() =>
// console.log(new Date), 1000)
},
beforeMount () {
// 3. 挂载前
console.log("beforeMount --- vue的虚拟DOM, 挂载到真实的网页之前")
console.log(document.getElementById("myUl")) // null
// console.log(document.getElementById("myUl").children[1].innerHTML) // 报错
},
mounted () {
// 4. 挂载后=> 操作dom
console.log("mounted --- vue的虚拟DOM, 挂载到真实的网页上 ")
// console.log(document.getElementById("myUl").children[1].innerHTML)
console.log(document.querySelector('#myUl').children[1].innerText)
},
beforeUpdate () {
// 5. 更新前
console.log("beforeUpdate --- 数据更新, 页面更新前")
// 比如点击新增数组元素, vue会触发此生命周期函数, 但是此时页面并未更新, 所以获取不到新增的li标签
// console.log(document.getElementById("myUl").children[4].innerHTML) // 报错
},
updated () {
// 6. 更新后
console.log("updated --- 数据更新, 页面更新后")
console.log(document.getElementById("myUl").children[4].innerHTML)
},
beforeDestroy () {
// 7. 销毁前
// (清除定时器 / 解绑js定义的事件)
console.log("beforeDestroy --- 实例销毁之前调用")
},
destroyed () {
// 8. 销毁后
// (清除定时器 / 解绑js定义的事件)
console.log("destroyed --- 销毁完成")
// clearInterval(this.time)
},
};
</script>
<style>
</style>
直接看效果
分析:
1.从这里可以看到在没有挂载到网页上之前数据是拿不到的
2.父与子的执行顺序,初始渲染时是先依次触发父组件的beforeCreate,created,beforeMount然后依次触发子组件的beforeCreate,created,beforeMount,mounted,最后再触发父组件的mounted
点击按钮更新页面,观察后续效果
分析:
1.此处可以看到子组件的beforeUpdate,updated两个钩子触发了
2.此时的子组件获取到了数据
3.父组件的更新钩子没有触发
问题:
那么销毁的钩子怎么触发呢?
就是字面意思销毁,那么怎么触发呢?
//在子组件的ul上添加 v-if="isShow"
<ul id="myUl" v-if="isShow">
//在子组件的data新增
isShow:true
//在父组件也进行相同操作
<MySon v-if="isShow"/>
data() {
return {
isShow:true
}
},
直接看效果
首先是对子组件进行操作
发现干掉它自己只能触发自身的beforeUpdate,updated
然后对父组件进行操作
发现依次触发了父组件的beforeUpdate,子组件的beforeDestroy和destroyed,然后又触发了父组件的updated