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">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
注意:
- {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">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
mounted中Vue已经把它的this维护成了vm。所以上面的代码中使用箭头函数的时候,this往外寻找就是vm。
挂载流程
下图中红圈mounted之前的部分都属于挂载部分。
红色圆框对应着生命周期函数
其中有几个注意点:
这个地方的create不是指的vm创建,而是数据监测、数据代理的创建
此处是可以进行DOM操作的,页面的效果也会发生变化。但是紧随其后
也就是说不管你此时如何操作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">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
n:1
},
methods: {
add(){
console.log('add')
this.n++
},
},
})
</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
我们可以借助template让容器里面什么都不写:
<body>
<!-- 准备好一个容器-->
<div id="root" :x="n">
</div>
</body>
<script type="text/javascript">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
注意:
- template后面跟字符串
- 如果不想全写在一行就要使用模板字符串,否则报错
- Vue会直接把template当作模板执行后面的步骤(解析生成真实DOM·····)。
- template里面只能有一个根元素,所以我们把他用div包裹(不要使用<template>标签去包裹,会报错)
- 注意:
在使用了template之后,我们的网页:
不使用template:
也就是说如果使用template,Vue会将整个绿色框里的东西替换掉整个红色框里的东西:
在这一步骤中我们可以看到Vue将真实的DOM节点在$el中存了一份,再去插入到页面之中。为什么这么做呢?
在前面我们说过Vue在进行新的虚拟DOM和旧的虚拟DOM比较的时候,会出现有的元素可以复用的情况。既然要复用我们就要有这个之前的元素才能去复用,所以说这个地方要存一份备用。
更新流程
销毁流程
当我们执行了vm.$destroy()之后,代表着Vue进入了销毁流程。不过我们要注意的是vm销毁了,但他的工作成果还在,也就是说页面还是正常显示的。只是说没有人帮我们继续管理DOM。
注意:
①这里的其他实例代表的是组件
②解绑的是所有的自定义事件监听器,而原生的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">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
当我们点击了销毁按钮之后,页面还是这样没有变。不过当我们再次去点击+1的时候页面是没有反应的,同时打开Vue开发者工具我们发现啥都没有了:
意思是说销毁监听,子组件,和事件监听器
在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">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
结果:
结果我们发现add()确实可以用,但是页面并没有发生变化。也就是说在beforeDestroy这一阶段,所有对数据的修改不会再发生更新。
生命周期总结
生命周期函数一共是8个,我们可以将它们看作4对:
- 将要创建 / 创建完毕
- 将要挂载 / 挂载完毕
- 将要更新 / 更新完毕
- 将要销毁 / 销毁完毕
对应着:
- beforeCreate() / created()
- beforeMount() / mounted()
- beforeUpdate() / updated()
- beforeDestroy() / destroyed()
接下来我们在开头的案例上添加一个需求:添加一个按键,点击之后透明度变化停止。
代码如下:
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="stop">点我停止变换</button>
</div>
</body>
<script type="text/javascript">
Vue.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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
为了能让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">
Vue.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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
我们发现在点击停止变换之后,在点击透明度变化为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">
Vue.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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
不要想着在stop中去关闭计时器,如果vm是因为其他原因销毁(也就是说不是通过点击按钮),那么stop也就不会被调用,计时器也就不会被关闭。所以最好是把关闭定时器的操作放在beforeDestroy()中。
销毁vm后定时器仍然是在计时的,我们可以在beforeDestroy()中把它关掉
其实还有3个钩子在生命周期图中并没有体现,他们在特定的场景中才会使用到,例如:路由切换。
常用的生命周期钩子:
- mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
- beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
- 销毁后借助Vue开发者工具看不到任何信息。
- 销毁后自定义事件会失效,但原生DOM事件依然有效。
- 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/zyb18507175502/article/details/125275748
- 点赞
- 收藏
- 关注作者
评论(0)