首先我们需要了解 Vue2 的生命周期,请参考我之前写的博文 Vue2-生命周期
Vue2 生命周期存在四个阶段,八个钩子函数,具体作用可以看图,详细解释可以参考之前的博文
Vue3 生命周期
经过对比,我们发现 Vue3 的生命周期也存在四个和 Vue2 完全一样的阶段,但是也存在一定的区别:
- 在销毁阶段的生命周期钩子函数改名了。
- 生命周期过程也存在部分变更。
配置式生命周期钩子函数对比
首先,这一块的内容叫做配置式生命周期钩子函数。之所以叫配置式,是因为我们采用的是和 Vue2 的生命周期一样的使用模式,同时也是为了和 Vue3 的组合式区分开来,组合式后面再开一part去讲,现在先讲讲配置式。
通过上面两幅图对比,我们可以很清楚的看到,Vue3 中关于组件销毁阶段和 Vue2 中不一致,分别是:
- 销毁前:beforeDestory ==> beforeMount
- 销毁后:destoryed ==> unmounted
然后就是整个生命周期流程也存在一定的改动:
- 初始化阶段:Vue2 通过 new Vue() 进行初始化。但是 Vue3 是先调用了 creatApp 创建了app 实例,并且传入了 el 属性,然后再去初始化。-- 这就导致了 在Vue3 中如果不传 el 属性,是无法进行下一步生命周期的,但是在Vue2 中,不传 el 属性,也可以继续往下走到 beforeMount
- created ==> beforeMount 阶段:Vue2 中进行了首先判断是否传递 el 属性,或者是否调用 $mount函数并传入 el 属性,然后再去判断是否传入 templete 模板。但是 Vue3 中只需要判断是否传入 templete 模板就行。这就和第一点呼应上了。因为 Vue3 最开始初始化就必须传入el属性,所以不用进行判断。
组合式生命周期钩子函数对比
既然是组合式,那就说明和配置式肯定是存在区别的:
- 需要像之前的 computed 计算属性,watch监听器之类的一样,需要先引入,再使用。
- 所有组合式生命周期钩子函数都应该在组件的
setup()
阶段被同步调用
上面是 Vue3 的组合式生命周期钩子函数,经过对比,我们可以发现存在以下几点明细的区别
- 创建阶段:Vue2生命周期中的组件创建阶段( beforeCreate、created ),在Vue3 中被移除,取而代之的是 setup 函数。这表示在创建阶段的钩子函数中的逻辑可以直接在Vue3 的setup中编写。
- 挂载、更新、销毁、keep-alive、错误捕获阶段:生命周期过程不变,只是钩子函数名称发生变化
- 调试阶段:新增两个调试阶段的钩子,当依赖被调用或依赖更新时调用。
Vue3 配置式API 和 组合式API 对比
上面讲了Vue2 和 Vue3 的生命周期对比,然后我们来看看 Vue3 中配置式和组合式生命周期到底有什么区别
配置式 | 组合式 | 作用 |
beforeCreate | 直接在 setup中执行 | 在实例初始化之后,数据观测 (reactivity ) 和事件/生命周期处理之前被调用。在这个阶段,组件实例还没有完全初始化,data 和 props 都不可用。 |
created | 直接在 setup中执行 | 在实例创建完成后调用,此时组件的响应式系统已经建立,但还没有挂载到 DOM 上。在这个钩子中,可以访问并修改响应式数据、调用方法等。 |
beforeMount | onBeforeMount | 当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程 |
mounted | onMounted | 在组件挂载完成后执行,这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端执行。也就是操作 DOM |
beforeUpdate | onBeforeUpdate | 在组件即将因为响应式状态变更而更新其 DOM 树之前调用,在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。 |
updated | onUpdated | 在组件因为响应式状态变更而更新其 DOM 树之后调用 |
beforeUnMount | onBeforeUnmount | 在组件实例被卸载之前调用,当这个钩子被调用时,组件实例依然还保有全部的功能 |
unmounted | onUnmounted | 组件实例被卸载之后调用,可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。 |
activated | onActivated | 若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用。 |
deactivated | onDeactivated | 若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用。 |
errorCaptured | onErrorCaptured | 在捕获了后代组件传递的错误时调用 |
-- | onRenderTracked | 当组件渲染过程中追踪到响应式依赖时调用。这个钩子仅在开发模式下可用 |
-- | onRenderTriggered | 当响应式依赖的变更触发了组件渲染时调用。这个钩子仅在开发模式下可用 |
-- | onServerPrefetch | 在组件实例在服务器上被渲染之前调用, 如果这个钩子返回了一个 Promise,服务端渲染会在渲染该组件前等待该 Promise 完成。 这个钩子仅会在服务端渲染中执行,可以用于执行一些仅存在于服务端的数据抓取过程。 |
其中有一些钩子需要详细解释一下:
1、onMounted:组件挂载完成后执行,可以再此操作DOM。组件在以下情况下被视为已挂载:
-
其所有同步子组件都已经被挂载 (不包含异步组件或
<Suspense>
树内的组件)。 -
其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。
-
案例:通过 ref 操作 DOM
// onMounted 钩子中 通过 ref 来操作DOM节点 <script setup> import { ref, onMounted } from 'vue' const el = ref() onMounted(() => { el.value // <div> }) </script> <template> <div ref="el"></div> </template>
2、onUpdated:在组件因为响应式状态变更而更新其 DOM 树之后调用
- 父组件的更新钩子将在其子组件的更新钩子之后调用。
-
这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的,因为多个状态变更可以在同一个渲染周期中批量执行 (考虑到性能因素)。如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。
-
不要在 updated 钩子中更改组件的状态,这可能会导致无限的更新循环!
- 案例:访问更新后的 DOM
<script setup> import { ref, onUpdated } from 'vue' const count = ref(0) onUpdated(() => { // 文本内容应该与当前的 `count.value` 一致 console.log(document.getElementById('count').textContent) }) </script> <template> <button id="count" @click="count++">{{ count }}</button> </template>
3、onUnmounted:组件实例被卸载之后调用。一个组件在以下情况下被视为已卸载:
-
其所有子组件都已经被卸载。
-
所有相关的响应式作用 (渲染作用以及
setup()
时创建的计算属性和侦听器) 都已经停止。 -
案例:清除定时器
<script setup> import { onMounted, onUnmounted } from 'vue' let intervalId onMounted(() => { intervalId = setInterval(() => { // ... }) }) onUnmounted(() => clearInterval(intervalId)) </script>
4、onErrorCaptured:在捕获了后代组件传递的错误时调用。这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串,错误可以从以下几个来源中捕获:
- 组件渲染
- 事件处理器
- 生命周期钩子
setup()
函数- 侦听器
- 自定义指令钩子
- 过渡钩子
总结
1、配置式中存在 beforeCreate 和 created 两个钩子,但是在组合式中却没有对应的钩子。这是因为在组合式中,setup
函数会在组件实例初始化的早期阶段执行,并且在这个阶段,props
和 context
已经可用。setup
函数的执行时间点大致相当于选项式 API 中的 beforeCreate
和 created
之间。因此,setup
本身就可以处理 beforeCreate
和 created
钩子中需要执行的逻辑,这使得它们变得不再必要。
2、新增两个可供调试的生命周期钩子:onRenderTracked、onRenderTriggered。这两个事件都带有一个debugger event,该事件会告诉你哪个操作跟踪了组件以及该操作的目标对象和键。
3、对于其他生命周期,组合式和配置式功能一致,只是在命名上存在差异
4、使用方面也存在差异,配置式参考Vue2生命周期使用,组合式则是在 先引入,然后在 setup 中通过函数注册的方式引用。
5、如果同时存在 配置式和组合式两种生命周期,那么会先执行组合式,然后在执行配置式。这是因为 setup 函数是在实例化之前执行的,而配置式生命周期使在new Vue 实例化之后才存在的。所以 setup 函数中的生命周期钩子也会在配置式之前执行
mounted() {
console.log('配置式 API: mounted');
},
setup() {
onMounted(() => {
console.log('组合式 API: onMounted');
});
},
6、Vue2 中生命周期和Vue3 配置式的生命周期大同小异,除了初始化阶段的流程、模板编译的判断、以及卸载阶段的名称之外,其他基本一致