1、什么是vue生命周期
每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期。在这个过程中,他经历了从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。
2、vue2的生命周期
2.1、8个生命周期函数
- beforeCreate(创建前):数据观测和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。
- created(创建后) :实例创建完成, 可以访问到data、computed、watch、methods上的方法和数据。但是此时渲染的节点还未挂载到 DOM,所以不能访问到
$el
属性(即 el: '#app')。 - beforeMount(挂载前):在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。此时模板编译完成 生成html,还没有挂载html到页面上,无法获取dom。未将html{{}}中的插值替换为data中的数据
- mounted(挂载后):在el被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。组件挂载完成,模板中的html渲染到页面中,能直接获取到dom。此过程中进行ajax交互。将html{{}}中的插值替换为data中的数据
- beforeUpdate(更新前):响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染。
- updated(更新后) :在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
- beforeDestroy(销毁前):实例销毁之前调用。这一步,实例仍然完全可用,
this
仍能获取到实例。 - destroyed(销毁后):实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。
注意:mouted和updated的执行,并不会等待所有子组件都被挂载完成后再执行,所以如果你希望所有视图都更新完毕后再做些什么事情,那么你最好在mouted或者updated中加一个$nextTick(),然后把要做的事情放在$netTick()中去做。
2.2、created和mounted的区别
- created: 在模板渲染成html前调用,即通常初始化某些属性值,此时视图中的html还没有渲染出来;
- mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。(此时html已经渲染出来了,所以可以直接操作dom节点)
例如:
Vue.component("demo1",{
data:function(){
return {
name:"",
age:"",
city:""
}
},
template:"<ul><li id='name'>{{name}}</li><li>{{age}}</li><li>{{city}}</li></ul>",
created:function(){
this.name="唐浩益"
this.age = "12"
this.city ="杭州"
var x = document.getElementById("name")//第一个命令台错误
console.log(x.innerHTML);
},
mounted:function(){
var x = document.getElementById("name")//第二个命令台输出的结果
console.log(x.innerHTML);
}
});
var vm = new Vue({
el:"#example1"
})
可以看到输出如下:
可以看到都在created赋予初始值的情况下成功渲染出来了。
但是同时看console台如下:
可以看到第一个报了错,实际是因为找不到id,getElementById(ID) 并没有找到元素,原因如下:
在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素;
在mounted中,由于此时html已经渲染出来了,所以可以直接操作dom节点,故输出了结果“唐浩益”。
2.3、vue2生命周期的过程举例
大致过程就是这样,下面我们来通过例子来看一看
(1)例1:没有template参数
<body>
<div id="app">
<p>{{message}}</p>
<button @click="changeMsg">改变</button>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'hello world'
},
methods: {
changeMsg () {
this.message = 'goodbye world'
}
},
beforeCreate() {
console.log('------初始化前------')
console.log(this.message) //undefined
//console.log(this.changeMsg) //undefined
console.log(this.$el) //undefined
},
created () {
console.log('------初始化完成------')
console.log(this.message) //hello world
//console.log(this.changeMsg) // changeMsg方法
console.log(this.$el) //undefined
},
beforeMount () {
console.log('------挂载前---------')
console.log(this.message) //hello world
console.log(this.$el) // <div id="app">...</div>
},
mounted () {
console.log('------挂载完成---------')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate () {
console.log('------更新前---------')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('------更新后---------')
console.log(this.message)
console.log(this.$el)
}
})
</script>
我们先看看首次加载时,输出了啥。从上面我们可以看出几点,
首次,只执行了4个生命周期,beforeCreate,created, beforeMount, mounted。
- 第一个生命周期beforeCreate中,我们拿不到data中的数据,因为这个时候数据还未初始化;
- created中,我们可以拿到data中的message数据了,因为初始化已经完成;
- beforeMount中,我们拿到了$el(就是页面中的#app),是渲染前的;
- mounted中,我们也拿到了$el,是渲染后的;
(2)例2:有template参数
var vm = new Vue({
el: '#app',
data: {
message: 'hello world'
},
template: '<div>我是模板内的{{message}}</div>',
methods: {
changeMsg () {
this.message = 'goodbye world'
}
},
beforeCreate() {
console.log('------初始化前------')
console.log(this.message)
console.log(this.$el)
},
created () {
console.log('------初始化完成------')
console.log(this.message)
console.log(this.$el)
},
beforeMount () {
console.log('------挂载前---------')
console.log(this.message)
console.log(this.$el)
},
mounted () {
console.log('------挂载完成---------')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate () {
console.log('------更新前---------')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('------更新后---------')
console.log(this.message)
console.log(this.$el)
}
})
在beforeMount的时候,$el还是#app。但是在mounted时,因为我们传了个template,就变成模板的div了。所以,他直接将这个template转换成render函数啦。再渲染成真实dom后,用渲染出来的真实dom替换了原来的$el。
3、vue3生命周期
3.1 vue3的生命周期函数
(1)Vue应用程序中有4个主要事件(8个主要钩子)。
-
创建 — 在组件创建时执行
-
挂载 — DOM 被挂载时执行
-
更新 — 当响应数据被修改时执行
-
销毁 — 在元素被销毁之前立即运行
(2)vue2和vue3生命周期对比
- 与vue2相比,我们需要将生命周期钩子导入到项目中,才能使用,这有助于保持项目的轻量性。如:import { onMounted } from 'vue'。
beforecate
和created
(它们被setup
方法本身所取代)
Vue2 | Vue3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestory | onBeforeUnmount |
destoryed | onUnmounted |
(3)其它的改进:
errorCaptured
-> onErrorCaptured
activated -> onActivated
deactivated -> onDeactivated
新增的钩子函数:
组合式 API 还提供了以下调试钩子函数:
- onRenderTracked
- onRenderTriggered
(4)vue3中的生命周期函数详解:
除了beforecate
和created
(它们被setup
方法本身所取代),我们可以在setup
方法中访问的API生命周期钩子有9个选项:
-
onBeforeMount
– 在挂载开始之前被调用:相关的render
函数首次被调用。 -
onMounted
– 组件挂载时调用 -
onBeforeUpdate
– 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。 -
onUpdated
– 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。 -
onBeforeUnmount – 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
-
onUnmounted
– 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。 -
onActivated
– 被keep-alive
缓存的组件激活时调用。 -
onDeactivated
– 被keep-alive
缓存的组件停用时调用。 -
onErrorCaptured
– 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回false
以阻止该错误继续向上传播。
注意:这些生命周期钩子注册函数只能在 setup() 期间同步使用。
(5)vue3生命周期使用实例
import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
},
}
4、 销毁生命周期的销毁过程
- vm.$destroy() 会触发 销毁前和销毁后的钩子函数,完全销毁一个实例。清理他与其它实例的连接,解绑他的全部指令和事件监听器(解绑全部的事件监听器指的是自定义的事件,例如为按钮添加的click事件)
- $destroy 方法 - 内部销毁。内部销毁只能销毁组件,不能销毁组件的dom结构。外部销毁不仅能销毁组件,也能销毁该组件的dom结构。
beforeDestroy
- 实例被销毁前调用,此时实例属性与方法仍可访问(如data、methods、指令等)。
destroyed
- 完全销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器(如:关闭定时器、取消订阅消息、解绑自定义事件clcik)。
- 并不能清除DOM,仅仅销毁实例