每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在 Vue 实例生命周期的不同阶段被调用的函数, 被称为生命周期钩子。这些生命周期钩子允许你执行特定的逻辑,比如在组件创建之前、创建之后、更新之前、更新之后、销毁之前等。
如图所示:
以下是 Vue 3 生命周期钩子的详细解释:
1、onMounted
钩子
注册一个回调函数,在组件挂载完成后执行:
function onMounted(callback: () => void): void
组件在以下情况下被视为已挂载:
- 其所有同步子组件都已经被挂载 (不包含异步组件或
<Suspense>
树内的组件)。 - 其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。
这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端执行。
这个钩子在服务器端渲染期间不会被调用。
<script setup>
import {onMounted,ref} from 'vue'
const status = ref('init')
onMounted(() => {
status.value = 'onMounted'
})
</script>
<template>
<p> {{"status = " + status}} </p>
</template>
2、onUpdated() 钩子
注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。
function onUpdated(callback: () => void): void
调用时机:
父组件的更新钩子将在其子组件的更新钩子之后调用。
这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的,因为多个状态变更可以在同一个渲染周期中批量执行 (考虑到性能因素)。
如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick()作为替代。
这个钩子在服务器端渲染期间不会被调用。
<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()
注册一个回调函数,在组件实例被卸载之后调用。
function onUnmounted(callback: () => void): void
一个组件在以下情况下被视为已卸载:
- 其所有子组件都已经被卸载。
- 所有相关的响应式作用 (渲染作用以及
setup()
时创建的计算属性和侦听器) 都已经停止。
可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。
这个钩子在服务器端渲染期间不会被调用。
<script setup>
import { onMounted, onUnmounted } from 'vue'
let intervalId
onMounted(() => {
intervalId = setInterval(() => {
// ...
})
})
onUnmounted(() => clearInterval(intervalId))
</script>
4、onBeforeMount()
注册一个钩子,在组件被挂载之前被调用。
function onBeforeMount(callback: () => void): void
当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。
这个钩子在服务器端渲染期间不会被调用。
5、onBeforeUpdate()
在组件即将因为响应式状态变更而更新其 DOM 树之前调用
function onBeforeUpdate(callback: () => void): void
这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。
这个钩子在服务器端渲染期间不会被调用。
6、onBeforeUnmount()
在组件实例被卸载之前调用
function onBeforeUnmount(callback: () => void): void
当这个钩子被调用时,组件实例依然还保有全部的功能。
7、onErrorCaptured()
在捕获了后代组件传递的错误时调用。
function onErrorCaptured(callback: ErrorCapturedHook): void
type ErrorCapturedHook = (
err: unknown,
instance: ComponentPublicInstance | null,
info: string
) => boolean | void
(1)、参数信息
这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串。
在生产环境中,第三个参数 (info
) 是一个缩短的代码,而不是含有完整信息的字符串。
生产环境的运行错误代码与其原始消息的映射表:
错误码 | 信息 |
---|---|
0 | setup function |
1 | render function |
2 | watcher getter |
3 | watcher callback |
4 | watcher cleanup function |
5 | native event handler |
6 | component event handler |
7 | vnode hook |
8 | directive hook |
9 | transition hook |
10 | app errorHandler |
11 | app warnHandler |
12 | ref function |
13 | async component loader |
14 | scheduler flush |
15 | component update |
16 | app unmount cleanup function |
sp | serverPrefetch hook |
bc | beforeCreate hook |
c | created hook |
bm | beforeMount hook |
m | mounted hook |
bu | beforeUpdate hook |
u | updated |
bum | beforeUnmount hook |
um | unmounted hook |
a | activated hook |
da | deactivated hook |
ec | errorCaptured hook |
rtc | renderTracked hook |
rtg | renderTriggered hook |
生产环境的编译错误代码与其原始消息的映射表:
错误码 | 信息 |
---|---|
0 | Illegal comment. |
1 | CDATA section is allowed only in XML context. |
2 | Duplicate attribute. |
3 | End tag cannot have attributes. |
4 | Illegal '/' in tags. |
5 | Unexpected EOF in tag. |
6 | Unexpected EOF in CDATA section. |
7 | Unexpected EOF in comment. |
8 | Unexpected EOF in script. |
9 | Unexpected EOF in tag. |
10 | Incorrectly closed comment. |
11 | Incorrectly opened comment. |
12 | Illegal tag name. Use '<' to print '<'. |
13 | Attribute value was expected. |
14 | End tag name was expected. |
15 | Whitespace was expected. |
16 | Unexpected '<!--' in comment. |
17 | Attribute name cannot contain U+0022 ("), U+0027 ('), and U+003C (<). |
18 | Unquoted attribute value cannot contain U+0022 ("), U+0027 ('), U+003C (<), U+003D (=), and U+0060 (`). |
19 | Attribute name cannot start with '='. |
20 | Unexpected null character. |
21 | '<?' is allowed only in XML context. |
22 | Illegal '/' in tags. |
23 | Invalid end tag. |
24 | Element is missing end tag. |
25 | Interpolation end sign was not found. |
26 | Legal directive name was expected. |
27 | End bracket for dynamic directive argument was not found. Note that dynamic directive argument cannot contain spaces. |
28 | v-if/v-else-if is missing expression. |
29 | v-if/else branches must use unique keys. |
30 | v-else/v-else-if has no adjacent v-if or v-else-if. |
31 | v-for is missing expression. |
32 | v-for has invalid expression. |
33 | key should be placed on the tag. |
34 | v-bind is missing expression. |
35 | v-on is missing expression. |
36 | Unexpected custom directive on outlet. |
37 | Mixed v-slot usage on both the component and nested . When there are multiple named slots, all slots should use syntax to avoid scope ambiguity. |
38 | Duplicate slot names found. |
39 | Extraneous children found when component already has explicitly named default slot. These children will be ignored. |
40 | v-slot can only be used on components or tags. |
41 | v-model is missing expression. |
42 | v-model value must be a valid JavaScript member expression. |
43 | v-model cannot be used on v-for or v-slot scope variables because they are not writable. |
44 | v-model cannot be used on a prop, because local prop bindings are not writable. Use a v-bind binding combined with a v-on listener that emits update:x event instead. |
45 | Error parsing JavaScript expression: |
46 | expects exactly one child component. |
47 | "prefixIdentifiers" option is not supported in this build of compiler. |
48 | ES module mode is not supported in this build of compiler. |
49 | "cacheHandlers" option is only supported when the "prefixIdentifiers" option is enabled. |
50 | "scopeId" option is only supported in module mode. |
51 | @vnode-* hooks in templates are no longer supported. Use the vue: prefix instead. For example, @vnode-mounted should be changed to @vue:mounted. @vnode-* hooks support has been removed in 3.4. |
52 | v-bind with same-name shorthand only allows static argument. |
53 | v-html is missing expression. |
54 | v-html will override element children. |
55 | v-text is missing expression. |
56 | v-text will override element children. |
57 | v-model can only be used on , and elements. |
58 | v-model argument is not supported on plain elements. |
59 | v-model cannot be used on file inputs since they are read-only. Use a v-on:change listener instead. |
60 | Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior. |
61 | v-show is missing expression. |
62 | expects exactly one child element or component. |
63 | Tags with side effect ( |
(2)、错误来源
错误可以从以下几个来源中捕获:
-
组件渲染
-
事件处理器
-
生命周期钩子
-
setup()
函数 -
侦听器
-
自定义指令钩子
-
过渡钩子
(3)、错误传递规则
- 默认情况下,所有的错误都会被发送到应用级的
app.config.errorHandler
,这样这些错误都能在一个统一的地方报告给分析服务。 - 如果组件的继承链或组件链上存在多个
errorCaptured
钩子,对于同一个错误,这些钩子会被按从底至上的顺序一一调用。这个过程被称为"向上传递",类似于原生 DOM 事件的冒泡机制。 - 如果
errorCaptured
钩子本身抛出了一个错误,那么这个错误和原来捕获到的错误都将被发送到app.config.errorHandler
。 errorCaptured
钩子可以通过返回false
来阻止错误继续向上传递。即表示"这个错误已经被处理了,应当被忽略",它将阻止其他的errorCaptured
钩子或app.config.errorHandler
因这个错误而被调用。