创建时间 2021 年 09 月 14 日
在翻阅 Vue 2 文档时,无意中看到示例代码里出现了一个奇怪的 event。链接在这
官方在介绍 $on
、$once
、$off
时,列举了一个例子:
mounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
'hook:beforeDestroy'
这玩意是啥,看原文介绍应该是等同于 beforeDestroy
这个生命周期钩子的。
在 Vue 源代码中检索了一下,终于在这里,找到了相对应的定义。
export function callHook(vm: Component, hook: string) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget()
const handlers = vm.$options[hook]
const info = `${hook} hook`
if (handlers) {
for (let i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, null, vm, info)
}
}
if (vm._hasHookEvent) {
// 注意这里
vm.$emit("hook:" + hook)
}
popTarget()
}
原来在 Vue 内部中,当生命周期函数被触发时,会同时触发一个以 hook:
开头的事件,而这个事件我们可以在组件内监听到。
这里稍微整理了一下事件的名称:
忽略前面的 hook: 就是正常的 选项生命周期函数
hook:beforeUpdate
hook:updated
hook:beforeCreate
hook:created
hook:beforeMount
hook:mounted
hook:beforeDestroy
hook:destroyed
hook:activated
hook:deactivated
知道了这用法后,就可以用来写一些"奇奇怪怪"的代码了。比如官方文档中提到的,可以在注册事件或者第三方库时顺便再把注销相关的逻辑给写上。
mounted(){
const someEvent = () => {/*...*/}
window.addEventListener("resize", someEvent)
this.$once("hook:beforeDestroy", () => {
window.addEventListener("resize", someEvent)
})
}
甚至你还可以在父组件监听子组件的生命周期
<Children @hook:mounted="handleChildrenMounted" />
由于 Vue 3 把 $on
$once
$off
这三个实例方法移除了(文档传送门)。所以在 Vue 3 中无法使用 this.$once("hook:xxx")
这种方式监听。但是这种方式还是可行。
<Children @hook:mounted="handleChildrenMounted" />
不推荐使用! 不推荐使用! 不推荐使用! 重要的事情说三遍。
特别是在 Vue 3 环境下,Vue 3 提供了更好用的 composition-api。
虽然看起来,有了这一 API 后,我们可以以更细的颗粒度去控制生命周期函数。但是, 正如 @posva 在该 issue中提到的:这并不是一个公共的 API。所以我们才没有在文档中找到相关的介绍。而这种没有明确在文档中提到的用法,我们在使用上要慎之又慎。因为我们无法得知是否在后续的某次更新中,Vue 会把这种用法给替代掉。