需求:打开页面,实现一段文本的透明度自动变化;

Vue2(笔记18) - Vue核心 - 生命周期_生命周期

提示:这个需求,需要这个标签在页面加载完成后,使用 setInterval(),定时器调整透明度;


引入生命周期

Vue引入 mounted 函数,当 Vue 完成模板的解析并把初始的真实DOM元素放入页面后(挂载完成)调用 mounted ;

<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>

提示:使用 setInterval( ) 定时器,不断修改透明度的值来完成渐变;

new Vue({
el:'#root',
data:{
opacity:1
},
// 完成模板的解析真实DOM挂载完成时,调用此函数
mounted() {
console.log("mounted");
setInterval(()=>{
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity =1
},16)
},
})

提示1:mounted() 函数是当完成模板解析、真实DOM安成挂载时执行;

提示2:setInterval() 定时器,的回调使用箭头函数,保证 this 是指向 vm ,而 mounted() 函数的this 就是 vm;

mounted() 是生命周期函数,是Vue在某个关键性的时候调用某个函数,函数体里的内容,由我们自己写;


【生命周期】

1)又名:生命周期回调函数、生命周期函数、生命周期钩子;

2)是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数(一个或几个);

3)生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的;

4)生命周期函数中的 this 指向的是 vm 或 组件实例对象;


Vue2(笔记18) - Vue核心 - 生命周期_生命周期_02

官网从创建Vue实例和最终销毁的全过程,一共经历了10个步骤:

1)其中共有8个生命周期函数(钩子函数)或叫4对生命周期函数;

2)大致可分为 生命周期(挂载)、生命周期(更新)、生命周期(销毁)这三大阶段;


生命周期_挂载流程

<div id="root">
<h3>当前n值是:{{n}}</h3>
<button @click="add">点我n+1</button>
</div>
new Vue({
el: '#root',
data: {
n: 1,
},
methods: {
add() {
this.n++
}
},
beforeCreate() {
console.log('beforCreate :', '此时的vm没有data和methods');
},
created() {
console.log('created :', '可以访问data中的数据和methods中的方法');
},
beforeMount() {
console.log('beforeMount :', '页面呈现未经Vue编译的DOM结构,此时对DOM的操作最终不会奏效');
},
mounted() {
console.log('mounted :', '初始化过程结束:页面呈现编译过DOM,对DOM的操作均有效;');
},

})

看下效果:

Vue2(笔记18) - Vue核心 - 生命周期_生命周期_03

上面代码在刷新页面时,就会执行的4个生命周期函数;

挂载阶段的四个生命周期函数,也可以理解为成对出现的 初始化前后挂载前后

各个生命周期函数的特性,用文章很难体现,只能结构流程图简要描述一下:

beforeCreate()  : 初始化之前;此时的 vm 还没有 data 和 methods

created() : 初始化之后;此时,可以访问 data 中的数据和 methods 中的方法;

beforMount() :挂载前;页面呈现出未经 Vue 编译的DOM结构,此时对 DOM 的操作最终也不会奏效;

mounted():挂载后;初始化过程结束,页面上呈现的是编译过真实 DOM,此时对 DOM 的操作均有效;


生命周期_更新流程

Vue2(笔记18) - Vue核心 - 生命周期_Vue_04

<div id="root">
<h3>当前n值是:{{n}}</h3>
<button @click="add">点我n+1</button>
</div>

还用上面的代码:添加数据更新前数据更新后的两个生命周期函数;

new Vue({
el: '#root',
data: {
n: 1,
},
methods: {
add() {
this.n++
console.log('add number ++')
}
},
beforeUpdate() {
console.log('beforUpdate :','此时,数据是新的,但页面是旧的,即:页面尚未和数据保持同步');
},
updated() {
console.log('updated :','此时,数据是新的,页面也是新的,即:页面和数据已经保持同步;');
console.log('数据更新');
},

})

在点击按钮时,输出 “add number ++ ”,更新完成后,输出 “数据更新”;

当数据改变的时候,就进入更新流程,这个流程中有两个生命周期函数:

beforUpdate() : 此时,数据是新的,但页面是旧的,即:页面尚未和数据保持同步;

updated():此时,数据是新的,页面也是新的,即:页面和数据已经保持同步;

看下结果:

Vue2(笔记18) - Vue核心 - 生命周期_8个钩子函数_05


生命周期_销毁流程

当执行 ​vm.$destroy()​ 方法时,就意味着当前实例要被销毁了;

<div id="root">
<h3>当前n值是:{{n}}</h3>
<button @click="add">点我n+1</button>
</div>
new Vue({
el: '#root',
data: {
n: 1,
},
methods: {
add() {
this.n++
console.log('add number ++')
}
},
beforeDestroy() {
console.log('beforDestroy :','此时,vm 中所有的 data、methods、指令都还在,但页面冻结了,马上要执行销毁过程。');
console.log('此时还能输出n:',this.n);
this.add()
},
destroyed() {
console.log('destroyed :','完全销毁一个实例,销毁所有实例的边接,解绑它的全部指令和事件监听器');
},
})

看下结果:点击销毁按钮;

Vue2(笔记18) - Vue核心 - 生命周期_8个钩子函数_06

在 beforDestroy() 函数里,还可以输出 n 和 调用 add() 方法,但页面已经不更新了;

销毁流程中也有两个生命周期函数(钩子函数):

beforeDestroy() :此时,vm 中所有的: data、methods、指令等等,都处于可用状态,马上要执行销毁过程。一般在此阶段:关闭定时器、取消订阅消息 、解绑自定义事件等收尾操作。

destroyed():此时,vm 不在了,实例身上的监视程序、子组件和事件监听等都没有了,页面冻结;一般这个阶段,什么也不干;


生命周期_总结

最后,把最开始的示例拿过来,补个需求:点击铵钮停止渐变,冻结页面

<div id="root">
<h2 :style="{opacity}" @click="stop">欢迎学习Vue</h2>
</div>

提示:添加点击事件,调用方法,清除 mounted() 钩子函数中的定时器,并销毁实例;

new Vue({
el: '#root',
data: {
opacity: 1
},
methods: {
stop() {
console.log("停止");
this.$destroy()
}
},
mounted() {
this.timer = setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 16)
},
beforeDestroy() {
console.log('实例将被销毁,清除定时器');
clearInterval(this.timer)
},
})

提示1:在 stop() 方法销毁实例,就等于彻底冻结了页面,渐变也就停了;

提示2:如果不清除定时器,即使销毁了实例,定时器还在运行,因为定时器不被 Vue 管理 ;

提示3:之所以要在 beforDestroy() 钩子中清除定时器,而不是在 stop() 中清除,是因为销毁实例的操作可能是其他组件完成的,也就是“自杀”变“他杀”,所以在 beforDestroy() 中清除最安全,也就是所谓的“善后操作”;

看下结果:

Vue2(笔记18) - Vue核心 - 生命周期_生命周期_07

点击按钮后, stop 执行, beforeDestroy 也执行,随后销毁实例,页面冻结;


从创建Vue实例到销毁实例之间,共4对,8个生命周期函数,即:

创建之前、创建完成;挂载之前,挂载完成;更新之前,更新完成;销毁之前,销毁完成;

“创建过程”,严格来说,不是Vue实例的创建,而是实例初始化(init)前后;

其实还有3个钩子没有讲到,放在路由讲完时再讲;


所以总结下生命周期全流程中的关键时刻:

将要创建 --> 调用 beforeCreate() 函数;

创建完成 --> 调用 created() 函数;

将要挂载 --> 调用 beforeMount() 函数;

挂载完成 --> 调用 mounted() 函数; 【重要的钩子】

将要更新 --> 调用 beforeUpdate() 函数;

更新完成 --> 调用 updated() 函数;

将要销毁 --> 调用 beforeDestroy() 函数; 【重要的钩子】

销毁完成 --> 调用 destroyed() 函数;


基于官方的流程图,做个解释示意图:

Vue2(笔记18) - Vue核心 - 生命周期_8个钩子函数_08

常用的生命周期钩子:

1) mounted() :发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等“初始化操作”;

2) beforeDestroy() :清除定时器、解绑自定义事件、取消订阅消息等“收尾工作”;


关于销毁Vue实例:

1)销毁后借助 Vue 开发者工具看不到任何信息;

2)销毁后自定义事件会失效,但原生 DOM 事件依然有效;

3)一般不会在 beforeDestroy() 钩子操作数据,因为即便操作数据,也不会再触发更新流程了;