Vue2 的@hook 、 hook: 与生命周期

  • Vue2 的@hook 、 hook: 与生命周期已关闭评论
  • 79 次浏览
  • A+
所属分类:Web前端
摘要

优点:简单易上手缺点:此种方法子组件必须是自己编写的组件,若引用第三方库这种方式则不可行


如何实现父组件监听子组件的生命周期

方法一:$emit

// 父组件 <template>   <div>     <Child       @mounted="onMounted"       @updated="onUpdated"       @beforeDestroy="onBeforeDestroy"     ></Child>   </div> </template>  // 子组件 ...   mounted () { 	  this.$emit('mounted')   }   updated () { 	  this.$emit('updated')   }   beforeDestroy () { 	  this.$emit('beforeDestroy')   } ...  

优点:简单易上手

缺点:此种方法子组件必须是自己编写的组件,若引用第三方库这种方式则不可行

方法二:@hook

// 父组件 <template>   <div>     <Child       @hook:mounted="onMounted"       @hook:updated="onUpdated"       @hook:beforeDestroy="onBeforeDestroy"     ></Child>   </div> </template>  // 子组件 <!--无-->  

官方文档并没有太多相关解释,只在处理边界情况 #程序化的事件侦听器— Vue.js (vuejs.org)里有出现。

子组件无需相关处理就能实现侦听,这块的实现原理可以从源码里探究部分

在组件生命周期的每个函数内都调用了callHook它支持两个参入,分别是实例vm和对应的生命周期钩子名称。而callHook里面就执行了vm.$emit('hook:' + hook),此为方法一!

当在子组件上传入了对应的@hook:mounted钩子,也就是执行了vm.$on('hook:mounted'),而vue实例在生命周期里本身就会执行vm.$emit('hook:mounted'),其实就连带着触发了我们绑定给子组件的回调函数了。

Vue2 的@hook 、 hook:  与生命周期
Vue2 的@hook 、 hook:  与生命周期

ps:使用callHook的好处

callHook(vm, 'beforeCreate') 调用后, const handlers = vm.$options[hook] 即读取到了当前 vm 实例上的任务队列,然后通过 for 循环依次传递给 invokeWithErrorHandling(handlers[i], vm, null, vm, info) 进行处理, 调用 invokeWithErrorHandling 如果发生异常, 则会统一报错处理。

拓展

1.hook:提升代码简洁性

在编写组件时,我们往往需要在各个生命周期里都针对某个业务逻辑做一些处理,业务散落在各个生命周期钩子里:

<script type="text/ecmascript-6"> export default {   mounted () {       // 挂载时执行一些业务A相关逻辑       // 挂载时执行一些业务B相关逻辑   }   updated () {       // 更新时执行一些业务A逻辑       // 更新时执行一些业务B逻辑       // 更新时执行一些业务C逻辑   }   beforeDestroy () {     // 销毁时执行一些业务A逻辑     // 销毁时执行一些业务C逻辑   } } </script>  

业务逻辑散落在各个生命周期里,有时候是不利于我们阅读代码的,尤其是当该业务是一个复杂的长段代码时,这个时候我们就可以考虑利用hook:来梳理某一块的业务代码,提升可阅读性:

<script type="text/ecmascript-6"> export default {   created() {     this.$on('hook:mounted', () => {       挂载时执行一些业务A相关逻辑     })     this.$on('hook:updated', () => {       挂载时执行一些业务A相关逻辑     })     this.$once('hook:beforeDestroy', () => {       挂载时执行一些业务A相关逻辑     })   } } </script>  

这样就可以将散落的业务逻辑,都在一个created钩子函数里书写完毕,而且仍保持原来的生命周期逻辑。

2.避免data里的无用变量的定义

例如我们在编写组件时会执行一些事件监听或者定时器函数,我们希望在组件销毁的时候都能去销毁这些监听或者定时器,但是由于夸生命周期的问题,常常会将定时器赋值给一个全局变量或者绑定到this上,然后在另一个生命周期里获取并执行销毁操作。

// 优化前 <script type="text/ecmascript-6"> export default {   data() {     return {         timer:null       }   }   mounted () {     this.timer = setInterval(() => { 	// todo     }, 1000);   }   beforeDestroy () {     clearInterval(this.timer)   } } </script>   // 优化后 <script type="text/ecmascript-6"> export default {   mounted () {     const timer = setInterval(() => { 	// todo     }, 1000);     this.$once('hook:beforeDestroy', function () {         clearInterval(timer)     })   } } </script>  

Vue3.X

参考 https://v3-migration.vuejs.org/zh/breaking-changes/vnode-lifecycle-events.html