1. 生命周期图示
- 先展示一波vue实例生命周期图示
2. vue实例从创建到销毁可能会经历的生命周期钩子函数有:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
- activated
- deactivated
- errorCaptured
2. 生命周期钩子函数具体介绍与功能实现
2.0 生命周期钩子函数总结
2.1 操作数据的钩子函数
- 操作数据的钩子函数包括beforeCreate、created;
- beforeCreate
- 定义:在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用;
- 调用beforeCreate时,数据的值还是undefined,并无法进行操作数据的动作;
- created
- 定义:数据侦听、计算属性、方法、事件/侦听器的回调函数已经配置完毕;
- 调用created时,数据已经被赋值,此时可以进行操作数据的动作;
- 但此时挂载阶段还没有开始;
- 代码展示
- 创建一个LifeCycle组件,用来展示实例生命周期函数效果;
<template>
<div class="box">
<div>生命周期{{ text }}</div>
</div>
</template>
<script>
export default {
name:'MyLifeCycle',
data() {
return {
text: "hello"
}
},
// 操作数据
beforeCreate() {
console.log(this.text);// undefined 无法操作数据
console.log('【初始必备】1:beforeCreate');
},
created() {
console.log(this.text); // 可以操作数据
console.log('【初始必备】2:created');
}
}
</script>
此时控制台打印出的结果是:
2.2 操作DOM的钩子函数
- 操作数据的钩子函数包括beforeMount、mounted
- beforeMount
- 定义:在挂载开始之前被调用,此时相关的render函数首次被调用;
- 此时的this.$el的值是undefined,还无法进行操作DOM的动作;
- mounted
- 定义:实例被挂载后调用,这时
el被新创建的vm.$el替换了; - 此时,this.$el是可以获取到DOM元素的;
- 注意:此时,并不能保证所有的子组件也被挂载完毕,如果希望整个视图都被渲染完毕后,在进行一些操作,可以在mounted函数中使用$nextTick;
- 代码展示
// 操作DOM
beforeMount() {
console.log(this.$el); // undefined不适合操作DOM
console.log('【初始必备】3:beforeMount');
},
mounted() {
console.log(this.$el); // 获取dom元素
// 改变按钮的颜色
// 在数据变更以后,渲染之后的下一次行为中执行
this.$nextTick(()=>{
this.$refs.btn.style.color = 'red';// 此时元素没有存在
});
console.log('【初始必备】4:mounted');
}
此时控制台打印出的结果是:
2.3 更新时调用的钩子函数
- 更新时调用的钩子函数有beforeUpdate、updated;
- beforeUpdate
- 定义:在数据发生改变后,DOM 被更新之前被调用;
- 此时this.$el指向更新前的DOM,可以在这里进行一些DOM元素修改前要进行的操作;
- updated
- 定义:在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用;
- 此时,已经可以拿到更新完成的DOM元素;
- 注意:在此期间应该避免进行更改状态(数据)的操作;
- 如需进行更改数据操作,应该选择computed或者watch属性来实现;
- 同样的,此时并不能保证所有子组件都被挂载完毕了,如果想在所有元素挂载完成后进行一些操作,可以在此钩子函数中使用$nextTick;
- 代码展示
- 增加空值text值修改的按钮组件,方便测试
<template>
<div class="box">
<div>生命周期{{ text }}</div>
<button @click="text = 'Hello Green'">修改text</button>
</div>
</template>
// 更新时
beforeUpdate() {
console.log(this.$el); // 更新前的DOM
console.log('【发生修改】5:beforeUpdate');
},
updated() {
console.log(this.$el); // 更新后的DOM
console.log('【发生修改】6:updated');
}
此时控制台打印出的结果是:
2.4 组件销毁时调用的钩子函数
- 组件销毁时时调用的钩子函数有beforeDestroy、destroyed;
- beforeDestroy
- 实例销毁之前调用,此时实例还是完全可用的;
- 注意:该钩子在服务器端渲染期间不被调用;
- 可以在此阶段手动进行DOM/定时器销毁事件,或者手动清除一些大数据,保证及时清除内存空间;
- destroyed
- 实例销毁后调用,此时所有实例包括子实例也都被销毁,vue指令都将失效;
- 一般没有必须在此阶段进行的操作;
- 代码展示
beforeDestroy() {
// DOM事件/定时器
// clearInterval(this.timer);
// this.bigData.length = 0; // 做了一大数据处理的注释
console.log('【销毁必备】7:beforeDestroy');
},
destroyed() {
console.log('【销毁必备】8:destroyed');
}
2.5 被keep-alive缓存组件的激活与失活钩子函数
- keep-alive
- 定义:是一种vue内置组件,作用就是缓存需要频繁变换状态的组件状态;
- 在keep-alive内包裹的组件,可以触发activated和deactivated 2个生命周期钩子函数;
- 作用在于避免频繁的创建与销毁组件, 缓存组件数据;
- 一些属性:
- 排除掉哪些组件 :exclude=“[组件名HelloWorld]” ,components中决定;
- 包含哪些组件: :include=“[组件名HelloWorld]” ,components中决定;
- max值为数字,表示最多缓存多少个组件, 是一种临界值 :max=“9”表示最多缓存9个组件,该属性主要为了避免缓存组件较多占用较大内存,造成卡顿;
- activated
- 定义:被 keep-alive 缓存的组件激活时调用;
- 相当于created的替换,被缓存的组件不用通过created函数创建,而是通过 activated钩子函数进行状态激活;
- deactivated
- 定义:被 keep-alive 缓存的组件失活时调用;
- 相当于deactivated的替换,隐藏被缓存的组件时,不用通过beforeDestroy函数销毁组件,而是通过deactivated钩子函数将组件状态设置为失活;
- 代码展示
- 在父组件中调用LifeCycle组件时,用keep-alive组件包裹;
- 定义一个button组件控制组件状态;
<keep-alive : include = "cached" exclude = "ACompoment" : max = "99">
<LifeCycle v-if="isExist" v-model="isExist" @close="doClose" />
</keep-alive>
<button @click="open">切换生命周期组件</button>
- 在父组件的components中声明引入的子组件,在cached数组中添加需要缓存状态的组件;
export default {
components: { LifeCycle },
data() {
return {
cached: [
'MyLifeCycle'
],
isExist: true
}
},
}
- 在父组件定义实现组件控制和组件状态转换的方法;
methods: {
open() {
this.isExist = !this.isExist;
if (!this.cached.includes('MyLifeCycle'))
this.cached.push('MyLifeCycle')
},
doClose(url) {
this.cached.splice(this.cached.indexOf(url), 1);
}
}
- LifeCycle组件中调用activated和deactivated钩子函数;
<template>
<div class="box">
<span style="position:absolute;right:6px;top:4px;cursor:pointer;" @click="close">X</span>
</div>
</template>
<script>
export default {
name:'MyLifeCycle',
methods:{
close(){
this.$emit('input',false);
this.$emit('close','MyLifeCycle');
},
activated() { // created的替换
console.log('【特殊场景】9:activated');
},
deactivated() { // beforeDestroy的替换
console.log('【特殊场景】10:deactivated');
}
}
</script>
- 界面效果:
- 点击切换生命周期按钮时,控制台打印如下:
- 点击右上角X,先取消组件缓存,此时再点击切换生命周期按钮时控制台打印:
2.6 errorCaptured(异常捕获钩子函数)
- 定义:捕获一个来自后代组件的错误时被调用,放到父组件, 就能捕获子组件, 非 异步的异常;
- 此函数可以返回 false 以阻止该错误继续向上传播;
- 一般在根组件return false,做日志的输出;
- 用来做错误日志收集系统,发ajax请求: 账号, 时间, 错误, 前后访问的页面行为;
- 代码展示
errorCaptured(e) {
console.log('【异常捕获】11:errorCaptured', e);
return false; // 再向上传播 就到了浏览器
}