vue create与beforeDestroy触发时机分析

115 阅读1分钟

问题起因

在项目开发中偶然碰到如下场景

// 某个vue组件
{
    create: () => {
        // Bus是数据总线
        Bus.$on("load")
    },
    beforeDestroy: () => {
        Bus.$off("load")
    }
}

当这个组件卸载,并且重新渲染后,就接收不到load事件了。

输出日志点后发现:竟然是先触发on方法,再触发的on方法,再触发的off方法。也就是先触发create再触发beforeDestroy

image.png

测试案例

创建一个简单的vue程序进行测试

<html>
  <head></head>
  <body>
    <div id="app">
      <component :is="curComp"></component>
      <button @click="changeComp">切换</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
      Vue.component("compA", {
        template: "<li>compA</li>",
        created: () => {
          console.log("compA create");
        },
        mounted: () => {
          console.log("compA mounted");
        },
        beforeDestroy: () => {
          console.log("compA beforeDestroy");
        },
      });
      Vue.component("compB", {
        template: "<li>compB</li>",
        created: () => {
          console.log("compB create");
        },
        mounted: () => {
          console.log("compB mounted");
        },
        beforeDestroy: () => {
          console.log("compB beforeDestroy");
        },
      });
      var app = new Vue({
        el: "#app",
        data: {
          curComp: "compB"
        },
        methods: {
          changeComp: function () {
            this.curComp = this.curComp === "compA" ? "compB" : "compA";
          }
        },
      });
    </script>
  </body>
</html>

切换时的情况确认了上述的想法:create在beforeDestroy之前调用

image.png

原理分析

要分析原理就不得不提diff算法了(为了研究这个问题又复习了一下相关原理(可以参考juejin.cn/post/736197…

  1. 当component变化时,因为是替换node,首尾匹配肯定是匹配不上了。这时候进入查找逻辑。
  2. 查找逻辑中,如果找不到就直接走createElm创建新的节点了。这时候就会触发create周期
  3. 在最后,vue才会将oldVNode中剩余的节点通过removeVnodes去掉,触发beforeDestroy周期

image.png

分析结束,确实与上述事实对应。最终在总线事件名后拼接了ip进行处理