生命周期简介
-
生命周期(Life Cycle)是指一个组件从创建→运行→销毁的整个阶段,强调的是一个时间段,
Vue所有功能的实现都是围绕生命周期进行的 -
作用: 实现组件数据管理和
DOM渲染两大重要功能 -
Vue完整的生命周期大致可分成三个阶段:- 挂载阶段:
beforeCreate、created、beforeMount、mounted - 更新阶段:
beforeUpdate、updated - 销毁阶段:
beforeDestroy、destroyed
- 挂载阶段:
生命周期钩子
- 生命周期钩子是由
Vue提供的内置函数,会伴随着组件的生命周期自动按次序执行 - 在
new Vue()实例后会自动执行初始化函数,初始化事件,生成Vue实例的生命周期
注意:生命周期强调的是时间段,生命周期钩子强调的是时间点
挂载阶段
- 为
Vue实例初始化一些事件、属性和响应式数据等 - 把
<template>模板编译成渲染函数render,并渲染到真实的DOM节点上,以及数据变更时执行更新操作
数据初始化
beforeCreate
- 执行初始化前,
beforeCreate函数无法进行任何操作,在当前阶段data、methods、computed、watch上的数据和方法都不能被访问 - 实例初始化后,进行数据侦听和事件/侦听器的配置之前同步调用
<div id="app" >
<h1>{{message}}</h1>
</div>
data(){
return {
message:'javaScript'
}
},
methods:{
run(){console.log('执行');}
},
beforeCreate(){
console.group("------beforeCreate创建前状态------");
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
}
created
- 实例创建完成后立即同步调用,进行初始化数据
- 至此,实例已完成处理
data、computed、methods、watch,可以访问到data中的数据和**methods中的方法**,已经为Vue实例开辟了内存空间 - 但是挂载还没开始,
Dom元素依旧拿不到,且$el property目前尚不可用
created(){
console.group("------created创建前状态------");
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
debugger
}
- 打个断点在开发者工具中查看,发现模板中仅有
app根标签
模板编译
-
在执行下一个生命周期钩子之前,首先会判断对象是否有el选项。
- 有el选项就继续向下编译模板
- 没有则停止编译,停止了生命周期,直到该
Vue实例上调用vm.$mount(el)
beforeMount
- 挂载前状态,此时页面中还没有当前组件的
DOM结构,只是把HTML结构渲染到浏览器 el仍然无法获取,所有对DOM的操作不会奏效
beforeMount(){
console.group("------beforeMount创建前状态------");
const h1 = document.querySelector("h1");
console.log(h1);
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
debugger
}
- 在进入下个生命周期前,
Vue会用内存中生成的虚拟DOM转化为真实DOM - 并将虚拟
DOM保存一份到$el中
mounted
- 挂载结束,虚拟
DOM已经挂载在了真实的元素上,至此可以拿到el DOM元素也加载到浏览器中,对DOM操作奏效
mounted(){
console.group("------mounted创建前状态------");
const h1 = document.querySelector("h1");
console.log("h1 : "+ h1)
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
debugger
}
- 此时可以看到,
app根元素下已经有了DOM元素
更新阶段
- 当数据发生改变时,触发对应组件的重新渲染
beforeUpdate
- 此时数据是新的,但页面是旧的,即页面未和数据保持同步
- 在
mounted钩子中修改数据,没有立即重新渲染页面,此时可看到DOM元素中的数据未重新渲染
mounted(){
this.message = 'python'
},
beforeUpdate(){
console.group("------beforeUpdate创建前状态------");
const h1 = document.querySelector("h1");
console.log("h1 : "+ h1)
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
debugger
}
updated
- 在这个钩子之前,
Vue根据最新的数据重新渲染组件的DOM结构 - 当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到
updated生命周期函数中 - 该钩子函数最少被触发0次,因为只有当数据发生变化时才会被触发
updated(){
console.group("------updated创建前状态------");
const h1 = document.querySelector("h1");
console.log("h1 : "+ h1)
console.log("message: " + this.message);
debugger
}
销毁阶段
- 把组件实例从父组件中删除,取消依赖监听和事件监听,并解绑所有指令
beforeDestroy
- 实例销毁之前调用
- 此时实例仍然完全可用,组件仍然处于工作状态
- 注意: 该钩子在服务器端渲染期间不被调用
- 在
updated钩子函数销毁实例,触发beforeDestroy钩子函数,但是仍然可以输出该组件的数据,事件监听,方法
updated(){
this.$destroy()
},
beforeDestroy(){
console.group("------beforeDestroy创建前状态------");
const h1 = document.querySelector("h1");
console.log("h1 : "+ h1)
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
debugger
}
destroyed
- 在
Vue实例销毁后调用 - 实例所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
- 注意: 在此函数内的代码仍会执行,所有东西都可以输出
mounted(){
this.$destroy()
},
destroyed(){
console.group("------destroyed创建前状态------");
this.message = 'java'
const h1 = document.querySelector("h1");
console.log("h1 : "+ h1)
console.log("el : " + this.$el); // $el是vue实例的根元素
console.log("data : " + this.$data);
console.log("message: " + this.message);
console.log("props: " + this.$props);
console.log("methods: " + this.run);
}
其他阶段
-
除了以上的8个钩子函数以外,还有以下三个钩子:
activateddeactivatederrorCaptured
activated
- 被
keep-alive缓存的组件激活时调用 - 当组件被激活时,会自动触发组件的
activated生命周期钩子
deactivated
-
当组件被缓存时,会自动触发组件的
deactivated生命周期钩子- 父组件
App
<!-- App.vue --> <keep-alive> <Count v-if="btn"/> </keep-alive> <keep-alive> <Child v-if="!btn"/> </keep-alive> <button @click="btn=!btn">隐藏/激活</button>- 子组件
Count
<!-- Count.vue --> <h1>Count</h1>// Count.vue activated(){ console.log('Count被激活'); }, deactivated(){ console.log('Count被缓存'); }- 子组件
Child
<!-- Child.vue --> <h1>Child</h1>// Child.vue activated(){ console.log('Child被激活'); }, deactivated(){ console.log('Child被缓存'); } - 父组件
-
此时一进入页面,首先看到的是
Child组件- 当点击按钮时,
Child组件会被缓存,Count组件会激活 - 再次点击按钮,
Count组件会被缓存,Child组件会激活
- 当点击按钮时,
errorCaptured
-
捕获一个来自后代组件的错误时被调用
-
此钩子会收到三个参数
- 错误对象
- 发生错误的组件实例
- 包含错误来源信息的字符串
-
此钩子可以返回
false以阻止该错误继续向上传播
// 子组件
mounted(){
a // 会报错
}
// 父组件
errorCaptured(err,el,str){
console.log(err);
console.log(el);
console.log(str);
}
在不同的生命周期钩子中适合做什么?
- created: 可以发起
Ajax请求,并可以对数据进行初始化之类的操作 - mounted: 可以获取
DOM并进行操作,例如初始化echart图表,也可以做Ajax请求 - beforeupdate: 访问现有的
DOM,手动移除一些添加的监听事件 - updated: 可以获取最新的
DOM,但不建议进行数据操作,避免进入死循环 - beforeDestroy: 销毁定时器,解绑全局事件,销毁插件对象
- activated、deactivated: tab切换组件时可以使用