7.Hook Event

Hook Event

什么是 Hook Event

Hook Event 是 Vue 的自定义事件结合生命周期钩子实现的一种从组件外部为组件注入额外生命周期方法的功能。

原理

callHook

Vue 的生命周期函数是通过一个叫 callHook 的方法来执行的

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
/**
* callHook(vm, 'mounted')
* 执行实例指定的生命周期钩子函数
* 如果实例设置有对应的 Hook Event,比如:<comp @hook:mounted="method" />,执行完生命周期函数之后,触发该事件的执行
* @param {*} vm 组件实例
* @param {*} hook 生命周期钩子函数
*/
export function callHook (vm: Component, hook: string) {
// 在执行生命周期钩子函数期间禁止依赖收集
pushTarget()
// 从实例配置对象中获取指定钩子函数,比如 mounted
const handlers = vm.$options[hook]
// mounted hook
const info = `${hook} hook`
if (handlers) {
// 通过 invokeWithErrorHandler 执行生命周期钩子
for (let i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, null, vm, info)
}
}
// Hook Event,如果设置了 Hook Event,比如 <comp @hook:mounted="method" />,则通过 $emit 触发该事件
// vm._hasHookEvent 标识组件是否有 hook event,这是在 vm.$on 中处理组件自定义事件时设置的
if (vm._hasHookEvent) {
// vm.$emit('hook:mounted')
vm.$emit('hook:' + hook)
}
// 关闭依赖收集
popTarget()
}

invokeWithErrorHandling

通用函数,这里用于执行生命周期钩子

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
/**
* 通用函数,执行指定函数 handler
* 传递进来的函数会被用 try catch 包裹,进行异常捕获处理
*/
export function invokeWithErrorHandling (
handler: Function,
context: any,
args: null | any[],
vm: any,
info: string
) {
let res
try {
// 执行传递进来的函数 handler,并将执行结果返回
res = args ? handler.apply(context, args) : handler.call(context)
if (res && !res._isVue && isPromise(res) && !res._handled) {
res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
// issue #9511
// avoid catch triggering multiple times when nested calls
res._handled = true
}
} catch (e) {
handleError(e, vm, info)
}
return res
}

vm.$on

设置 vm._hasHookEvent,表示组件是否有 hook event,如果有的话,callHook 中会在生命周期钩子执行完毕后执行。

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
/**
* 监听实例上的自定义事件,vm._event = { eventName: [fn1, ...], ... }
* @param {*} event 单个的事件名称或者有多个事件名组成的数组
* @param {*} fn 当 event 被触发时执行的回调函数
* @returns
*/
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
if (Array.isArray(event)) {
// event 是有多个事件名组成的数组,则遍历这些事件,依次递归调用 $on
for (let i = 0, l = event.length; i < l; i++) {
vm.$on(event[i], fn)
}
} else {
// 将注册的事件和回调以键值对的形式存储到 vm._event 对象中 vm._event = { eventName: [fn1, ...] }
(vm._events[event] || (vm._events[event] = [])).push(fn)
// hookEvent,提供从外部为组件实例注入声明周期方法的机会
// 比如从组件外部为组件的 mounted 方法注入额外的逻辑
// 该能力是结合 callhook 方法实现的
// 正则判断 event 的名字是否有 hook
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
}
return vm
}

面试题

什么是 Hook Event?

Hook Event 是 Vue 的自定义事件结合生命周期钩子实现的一种从组件外部为组件注入额外生命周期方法的功能。


Hook Event 是如果实现的?

1
<comp @hook:lifecycleMethod="method" />
  • 处理组件自定义事件的时候(vm.$on) 如果发现组件有 hook:xx 格式的事件(xx 为 Vue 的生命周期函数),则将 vm._hasHookEvent 置为 true,表示该组件有 Hook Event
  • 在组件生命周期方法被触发的时候,内部会通过 callHook 方法来执行这些生命周期函数,在生命周期函数执行之后,如果发现 vm._hasHookEvent 为 true,则表示当前组件有 Hook Event,通过 vm.$emit('hook:xx') 触发 Hook Event 的执行

这就是 Hook Event 的实现原理。

参考

https://juejin.cn/post/6954923081462710309


7.Hook Event
http://example.com/2022/10/25/7-Hook-Event/
Author
John Doe
Posted on
October 25, 2022
Licensed under