0
点赞
收藏
分享

微信扫一扫

Vue核心⑬(生命周期)


文章目录

  • ​​生命周期引入​​
  • ​​挂载流程​​
  • ​​更新流程​​
  • ​​销毁流程​​
  • ​​生命周期总结​​

生命周期引入

​生命周期​​:

  • 又名:生命周期回调函数、生命周期函数、生命周期钩子。
  • 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
  • 生命周期函数中的this指向是 vm 或 组件实例对象。

例如我们现在有一个需求,页面上显示一行文字,并且动态的改变它的透明度。

代码如下:

<body>
<!-- 准备好一个容器-->
<div id="root">
<!--<h2 :style="{opacity:opacity}">欢迎学习Vue</h2> 因为重名所以可以写成对象的简写形式-->
<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>

<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {

},


//通过外部的定时器实现(不推荐)
setInterval(() => {
vm.opacity -= 0.01
if(vm.opacity <= 0) vm.opacity = 1
},16)</script>

注意:

  • {opacity}使用了对象的简写形式
  • 因为定时器在vm的外面,所以我们要获取opacity就可以通过数据代理从vm上获得
  • 因为小数的运算在js中是不准确的,所以我们没有写成vm.opacity === 0,而是写成vm.opacity <= 0

这样写可以实现功能,但是Vue实例与处理逻辑分开了,且处理逻辑还在操作Vue中的数据。也就是说从功能上来讲两者连在一起,但是从代码层面上来讲,他们俩是割裂开的。我们希望将这个逻辑放入到Vue中去。

此时我们就可以借助生命周期函数。在Vue完成模板的解析并把真实DOM全部​​挂载​​到页面上完毕之后,会调用一个mounted()函数,我们可以借助它来完成这个案例:

​挂载​​就是第一次把真实DOM放入到页面中

<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>

<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {

},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
setInterval(() => {
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
})

//通过外部的定时器实现(不推荐)
/* setInterval(() => {
vm.opacity -= 0.01
if(vm.opacity <= 0) vm.opacity = 1
},16) */</script>

mounted中Vue已经把它的this维护成了vm。所以上面的代码中使用箭头函数的时候,this往外寻找就是vm。

挂载流程

下图中红圈mounted之前的部分都属于挂载部分。

红色圆框对应着生命周期函数

Vue核心⑬(生命周期)_前端


其中有几个注意点:

Vue核心⑬(生命周期)_生命周期_02


这个地方的create不是指的vm创建,而是数据监测、数据代理的创建

Vue核心⑬(生命周期)_vue.js_03


此处是可以进行DOM操作的,页面的效果也会发生变化。但是紧随其后

Vue核心⑬(生命周期)_javascript_04


也就是说不管你此时如何操作DOM,当Vue把虚拟DOM转为真实DOM之后,你原来操作的效果都会消失。

template是什么?
例如我们现在有一段代码:

<body>
<!-- 准备好一个容器-->
<div id="root" :x="n">
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
</div>
</body>
<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
},

})</script>

我们可以借助template让容器里面什么都不写:

<body>
<!-- 准备好一个容器-->
<div id="root" :x="n">

</div>
</body>
<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
template:`
<div>
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
</div>
`,
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
},

})</script>

注意:

  • template后面跟字符串
  • 如果不想全写在一行就要使用模板字符串,否则报错
  • Vue会直接把template当作模板执行后面的步骤(解析生成真实DOM·····)。
  • template里面只能有一个根元素,所以我们把他用div包裹(不要使用<template>标签去包裹,会报错)
  • 注意:

在使用了template之后,我们的网页:

Vue核心⑬(生命周期)_前端_05


不使用template:


Vue核心⑬(生命周期)_vue.js_06


也就是说如果使用template,Vue会将整个绿色框里的东西替换掉整个红色框里的东西:


Vue核心⑬(生命周期)_javascript_07

Vue核心⑬(生命周期)_vue.js_08


在这一步骤中我们可以看到Vue将真实的DOM节点在$el中存了一份,再去插入到页面之中。为什么这么做呢?


在前面我们说过Vue在进行新的虚拟DOM和旧的虚拟DOM比较的时候,会出现有的元素可以复用的情况。既然要复用我们就要有这个之前的元素才能去复用,所以说这个地方要存一份备用。

更新流程

Vue核心⑬(生命周期)_javascript_09

销毁流程

Vue核心⑬(生命周期)_前端_10


当我们执行了vm.$destroy()之后,代表着Vue进入了销毁流程。不过我们要注意的是vm销毁了,但他的工作成果还在,也就是说页面还是正常显示的。只是说没有人帮我们继续管理DOM。

Vue核心⑬(生命周期)_vue.js_11


注意:


①这里的其他实例代表的是组件


②解绑的是所有的自定义事件监听器,而原生的DOM事件监听器仍是有效的

例如:

<body>
<!-- 准备好一个容器-->
<div id="root" :x="n">
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
<button @click="bye">点我销毁vm</button>
</div>
</body>
<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
bye(){
console.log('bye')
this.$destroy()
}
},
})</script>

Vue核心⑬(生命周期)_数据_12


当我们点击了销毁按钮之后,页面还是这样没有变。不过当我们再次去点击+1的时候页面是没有反应的,同时打开Vue开发者工具我们发现啥都没有了:

Vue核心⑬(生命周期)_javascript_13

Vue核心⑬(生命周期)_javascript_14


意思是说销毁监听,子组件,和事件监听器

Vue核心⑬(生命周期)_javascript_15


在beforeDestroy这一部分,图中的文字告诉我们data、methods、指令等都是可用的。我们可以试一下:

<body>
<!-- 准备好一个容器-->
<div id="root" :x="n">
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
<button @click="bye">点我销毁vm</button>
</div>
</body>
<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
bye(){
console.log('bye')
this.$destroy()
}
},
beforeDestroy() {
console.log('beforeDestroy')
this.add()
},
destroyed() {
console.log('destroyed')
},
})</script>

结果:

Vue核心⑬(生命周期)_javascript_16


结果我们发现add()确实可以用,但是页面并没有发生变化。也就是说在beforeDestroy这一阶段,所有对数据的修改不会再发生更新。

生命周期总结

生命周期函数一共是8个,我们可以将它们看作4对:

  • 将要创建 / 创建完毕
  • 将要挂载 / 挂载完毕
  • 将要更新 / 更新完毕
  • 将要销毁 / 销毁完毕

对应着:

  • beforeCreate() / created()
  • beforeMount() / mounted()
  • beforeUpdate() / updated()
  • beforeDestroy() / destroyed()

Vue核心⑬(生命周期)_javascript_17

接下来我们在开头的案例上添加一个需求:添加一个按键,点击之后透明度变化停止。

代码如下:

<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="stop">点我停止变换</button>
</div>
</body>

<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
clearInterval(this.timer)
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
})</script>

为了能让methods中的stop方法能访问到定时器,我们可以把定时器添加到vm身上。当然使用变量提升也是可以的。

如果我们再添加一个按钮:将透明度设置为1。代码如下:

<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>
</body>

<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
clearInterval(this.timer)
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
})</script>

我们发现在点击停止变换之后,在点击透明度变化为1的按钮仍然是奏效的。

我们可以使用另外一种暴力的方法停止变换,使用$destroy():

<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>
</body>

<script type="text/javascript">.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
this.$destroy()
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
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)
},
})</script>

不要想着在stop中去关闭计时器,如果vm是因为其他原因销毁(也就是说不是通过点击按钮),那么stop也就不会被调用,计时器也就不会被关闭。所以最好是把关闭定时器的操作放在beforeDestroy()中。

销毁vm后定时器仍然是在计时的,我们可以在beforeDestroy()中把它关掉

其实还有3个钩子在生命周期图中并没有体现,他们在特定的场景中才会使用到,例如:路由切换。

常用的生命周期钩子:

  • mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
  • beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

关于销毁Vue实例

  • 销毁后借助Vue开发者工具看不到任何信息。
  • 销毁后自定义事件会失效,但原生DOM事件依然有效。
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。


举报

相关推荐

0 条评论