• 声明:文章摘自https://www.cnblogs.com/goloving/p/13879157.html

Vue的各生命周期,其实就是Vue开发者规定的一些hook,和git里面规定的hook类似,你只要往hook里面填自定义内容,它就可以执行。如vue实例里的beforeCreate,created,mounted等,都是hook。

简单来说,hook其实就是一种回调函数,只不过这种回调函数的名称已经被固定,内容不固定,且函数名称作为了一个接口被暴露出去。这样也更好了进行了抽象化:将经常变化的内容抽象暴露出去,将固定不变的代码进行封装。

假如Vue生命周期没有设计Hook,那么自定义的一些业务逻辑将深深与框架本身耦合,也就是说,你要在框架内部去写业务逻辑。

VUE生命周期中hook源码浅析

1、在vue源码的/src/core/instance/lifecycle.js,有Vue生命周期的定义和hook的实现,callHook方法是触发hook之后的执行函数:
在这里插入图片描述
第一个参数vm是传入的vue实例,handlers选取的vue实例里关于特定hook的所有方法。这里简单猜测一下vm.$options中的内容

vm.$options = {
‘beforeCreate’:[
function a (){},
function b (){},
… // a,b均是自己在实例里面定义的
],
‘created’:[],
‘beforeMount’:[],
‘mounted’:[]

}
  遍历handlers将会遍历出在指定生命周期里开发者定义的不同方法,handler[i].call(vm)则是在vm的上下分环境下去执行handler[i]。

第二个参数则是上文提到的指定的hook string,诸如beforeCreate,created,beforeMount,mounted…

2、我们再看下在哪里调用的callHook,同样在/src/core/instance/lifecycle.js里:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  可以看到:在不同的生命周期执行函数里都执行了一次callHook,那么如果开发者在实例中的指定生命周期内定义了方法,这些方法就会在callHook里被执行(以实例的上下文)

简单应用

1、看到过一个 Vue 开发技巧,讲的是关于处理组件内定时器的步骤。通常我们一般都是这样操作的:

<script>
  export default {
    mounted() {
      this.timer = setInterval(() => { ... }, 1000);
    },
    beforeDestroy() {
      clearInterval(this.timer);
    }
  };
</script>

但是其实更好的做法是:

<script>
  export default {
    mounted() {
      const timer = setInterval(() => { ... }, 1000);
      this.$once('hook:beforeDestroy', () => clearInterval(timer);)
    }
  };
</script>

好处不用多说,单看代码量就少了很多。

先不说 hook:beforeDestroy 到底是啥。只是一番学习下来,发现这个示例最原始版本是来自 vue 官网。处理边界情况 — Vue.js​cn.vuejs.org,程序化的事件侦听器里有描述。

从语法上来看,就是组件内的生命周期函数在执行结束后会 $emit 一个 hook + 生命周期名字 的自定义事件。

这样的话,我们就可以在一个生命周期方法里监听其余生命周期的发生。一些情况下确实可以达到优化或简化代码的效果。比如到多个生命周期的逻辑都非常简单,简单到只有一句时,这个时候就可以考虑将这些代码放在 created 或者 mounted 里通过这种方式来监听并执行那些简单逻辑。上面的是在组件内的使用,在组件外的使用同样简单。

当组件内的生命周期函数在执行结束后 $emit 的自定义事件,不仅仅可以在组件内被 $on,vue 的语法决定了这些事件也可以被父组件 v-on 到,这样事情就变得有意思了。

设想一个场景如果我们需要在数据渲染到页面的之前让页面loading。mounted 之后停止 loading。beforeUpdata 时开始loading。updatad 之后停止 loading。最简单的方法就是改写组件的生命周期函数,使其在mounted/beforeUpdata /updatad 时通知父组件显示或者隐藏 loading。这样做显示不好,因为侵入了自组件的逻辑,增加的逻辑也和组件本身的功能好不关联。最好的办法就是使用
  v-on=“hook:xxx” 的方式:

<v-chart
    @hook:mounted="loading = false"
    @hook:beforeUpdated="loading = true"
    @hook:updated="loading = false"
    :data="data"
/>

这样,就实现了对子组件生命周期的监听。对任意的组件都有效果,包括引入的第三方组件。

2、总结一下:

当我们需要在父组件上知道子组件什么时候被创建、挂载或者是更新,特别是当为原生js库创建组件时,可以通过使用 @hook: 前缀监听生命周期中的钩子,并指定回调函数。

举个例子,如果你想要在第三方组件v-runtime-template渲染时做一些事情,那么你可以监听它的生命周期中的updated钩子

<v-runtime-template @hook:updated="doSomething" :template="template" />

你可能知道有一些方法可以在你自己的组件上,实现以上的需求。举个例子,通过在子组件的生命周期的钩子函数中,触发事件:

mounted() {
  this.$emit("mounted");
}

然后你就可以在父组件中这样做:

<Child @mounted="handleFn"/>

如果是在第三方组件时,是没办法这样实现的,取而代之的方法就是使用@hook前缀监听生命周期中的钩子,并指定回调函数。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐