1、引入生命周期
假设有这么一个案例,打开一个页面,上面显示的内容在不断地由清晰到模糊的变化,也就是说不断地改变透明度,应该如何实现这么一个案例呢?
1.1、搭建页面结构
<div id="root">
<h2 :style="{opacity}">{
{msg}}</h2>
</div>
<script>
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
opacity: 1,
msg: 'vue的生命周期'
}
})
</script>
一种很容易想到的思路是我们在外部开一个定时器,就像下面这样
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
opacity: 1,
msg: 'vue的生命周期'
}
})
setInterval(() => {
vm.opacity -= 0.01
if(vm.opacity <= 0) vm.opacity = 1
}, 16)
静态图不方便展示,但实际上是可以看到效果的。
但这样做的有不好的地方,我们在vue对象管理的外部写入了其他的脚本,而且还修改了vm中的属性,实际情况下,我们不会用vm来接收vue对象。
另一种思路是我们写一个回调函数
methods: {
change() {
setInterval(() => {
console.log('调用了定时器')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
}, 16)
}
}
由于一开始就需要显示效果,不能绑定时间来调用回调函数,所以在结构中用插值语法调用回调函数。
<div id="root">
<h2 :style="{opacity}">{
{msg}}</h2>
{
{change()}}
</div>
有一个十分鬼畜的事情是页面一直闪烁,并且调用了很多定时器,这是因为定时器会修改属性的值,属性一但被修改,就要重新解析模板,一旦重新解析模板,就要继续调用计时器,形成了一个恶性循环。
有什么解决方法呢?
我们设想只调用一次定时器,以后就不再调用了,也就是说只在一个时间点调用定时器,过了这个时间点就不会调用了。怎么控制好这个时间点呢,或者说在哪个时间调用呢?vue为我们提供了这么一个函数,代表特定的时间点mounted
mounted
是一个属于vue对象的函数。
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
opacity: 1,
msg: 'vue的生命周期'
},
mounted() {
setInterval(() => {
console.log('调用了定时器')
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 16)
}
})
需求得到了解决。
在这里说明一下,mounted
调用的时机只有一次,也就是说他只在vue
对象的生存时期只调用一次,像这样的函数,我们就叫作生命周期函数,它们组成了vue的生命周期。
2、vue的生命周期函数
vue的生命周期函数又叫做生命周期钩子。
下面给一张图来展示vue的生命周期:
下面分阶段来解释vue的生命周期
2.1、挂载流程
beforeCreate
beforeCreate
是第一个生命周期函数,这里的create,指的是创建数据代理,既然数据代理没有创建,则此时vue就无法获取到data中的属性,以及methods中的方法,我们可以举个例子,在beforeCreate
中卡个断点。
<div id="root">
<h2 v-text="n"></h2>
<h2>当前的n值是:{
{n}}</h2>
<button @click="add">点我n+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
data: {
n: 1
},
methods: {
add() {
console.log('add')
this.n++
},
},
beforeCreate() {
console.log('beforeCreate', this)
debugger
},
})
</script>
此时的this
指的是vue
的实例对象。
开发者工具为黑色。
我们发现发现此时页面无法获取到n的值,并且add方法也无法执行,跳过断点后
一切正常,这也就验证了在beforeCreate
阶段,我们无法获取到data中的属性,以及methods中的方法。
created
在created
这个阶段,数据代理已经创建完毕,可以获取到data中的属性,以及methods中的方法,依旧是断点方式验证,不要忘记删除之前的断点
created() {
console.log('created', this.n)
debugger
}
可以获取到data中的属性,但此时页面还没有解析。
beforeMount
在这个阶段,页面呈现出未解析的状态,此时可以修改Dom,但即便修改了,最终也不会奏效,因为接下来解析模板时,会替换Dom结构。
beforeMount() {
console.log('beforeMount')
debugger
}
Dom可以修改,放行之后不奏效
mounted
这是我们引入生命周期的时候用到的,在这一步,页面显示的是解析后的结构,并且对Dom的修改是有效的,但要尽量避免,此时可以进行一些初始化操作,如开启定时器,订阅一个消息等。
mounted() {
console.log('mounted')
debugger
}
至此,挂载流程结束。
2.2、更新流程
beforeUpdate
在这一阶段,数据已经发生了更新,但页面还是旧的,即数据还有页面没有同步
beforeUpdate() {
console.log('beforeUpdate', this.n)
debugger
}
点击n+1后,进入断点
控制台显示n值为2,但页面未更新,接着根据新数据更新Dom,完成Model和view的同步。
updated
在这一阶段,数据已经发生了更新,页面也是新的,即数据和页面同步
updated() {
console.log('updated')
debugger
}
点击加1后发现
2.3、销毁流程
销毁流程我们需要通过vue
中的$destroy
来实现。
这里的实例指的是组件实例。
beforeDestroy
此时: vm中所有的: data、methods、指令等等,都处于可用状态,马上要执行销毁过程,一般在此阶段:关闭定时器、取消订阅消息.解绑自定义事件等收尾操作。
beforeDestroy() {
console.log('beforeDestroy')
}
销毁vm后,点击add页面已经不发生变化了,输出add是因为一开始就绑定了事件,这个事件是原生的事件。
在这一阶段可以销毁引例中的定时器了。
mounted(){
console.log('mounted',this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
beforeDestroy() {
clearInterval(this.timer)
console.log('vm即将驾鹤西游了')
},
destroyed
在开发中用处不大,在这里就不过多赘述了。
3、vue的生命周期总结
常用的生命周期钩子:
mounted
: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。beforeDestroy
: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
- 销毁后借助Vue开发者工具看不到任何信息。
- 销毁后自定义事件会失效,但原生DOM事件依然有效。
- 一般不会在
beforeDestroy
操作数据,因为即便操作数据,也不会再触发更新流程了。
在这里借用Vue官网的一句话:你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。