Vue老鸟?那你肯定知道监控生命周期的技巧吧!

410 阅读5分钟

前言

Hello~大家好。我是秋天的一阵风

在 Vue 的世界里,生命周期钩子是每个组件成长的见证。从组件的出生到消逝,每个阶段都有特定的钩子,让我们可以洞察并参与组件的每一个重要时刻。但是,当被问到 “如何监听这些生命周期事件” 这个问题时,你是否能迅速回答出来?或者,你是否突然感到有些迷茫?

在我们揭晓答案之前,让我们先简单回顾一下 Vue 2Vue 3 的生命周期知识。这将帮助我们更好地理解如何监听这些关键的生命周期事件。

一、Vue2 与 Vue3 生命周期的区别

Vue 2 生命周期钩子Vue 3 生命周期钩子描述
beforeCreate无直接对应在 Vue 3 中,beforeCreate 的功能被 setup() 钩子覆盖。在 setup() 中,你可以访问到 props 和 context,但不能访问到 this
createdsetup()在 Vue 3 中,created 的功能被 setup() 钩子覆盖。在 setup() 中,你可以访问到 props 和 context,但不能访问到 this
beforeMountonBeforeMount在组件挂载到 DOM 之前调用。
mountedonMounted在组件挂载完成后调用。
beforeUpdateonBeforeUpdate在组件即将更新之前调用。
updatedonUpdated在组件更新后调用。
beforeDestroyonBeforeUnmount在组件即将卸载之前调用。
destroyedonUnmounted在组件卸载后调用。
errorCapturedonErrorCaptured当捕获一个来自子孙组件的错误时被调用。

🎯 关于 errorCaptured 生命周期

errorCaptured 是一个相对冷门但极其强大的生命周期钩子,它允许你在组件及其子组件中捕获未处理的错误。这对于全局错误监控和自定义错误处理策略非常有用。

如果你对这个钩子感兴趣,强烈推荐你阅读以下文章,深入了解其工作原理和应用场景:

🔎 深入 Vue 3 生命周期的源码实现

如果你对 Vue 3 生命周期的源码实现感兴趣,或者想了解 Vue 3 生命周期钩子的执行过程,以下文章将为你揭开神秘的面纱:

除此之外,Vue.js 3.0 还新增了两个用于调试的生命周期 API:onRenderTrackedonRenderTriggered

更多的生命周期API信息你可以在这里阅读:组合式API:生命周期钩子

二、Vue2中监听生命周期

我们来看一个简单的例子,下面代码例子中注册了多个生命周期方法,在组件对应的生命周期中会执行。

<template>
  <div>
    <h1>Vue 2 生命周期示例</h1>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "Hello Vue 2",
    };
  },
  beforeCreate() {
    console.log("beforeCreate: 实例刚刚被创建,data 和 methods 还未初始化");
  },
  created() {
    console.log("created: 实例创建完成,data 和 methods 已初始化");
  },
  beforeMount() {
    console.log("beforeMount: 挂载开始之前,模板已编译,但尚未挂载到 DOM");
  },
  mounted() {
    console.log("mounted: 挂载完成,模板已渲染到 DOM");
  },
  beforeUpdate() {
    console.log("beforeUpdate: 数据更新之前,虚拟 DOM 还未更新");
  },
  updated() {
    console.log("updated: 数据更新完成,虚拟 DOM 和真实 DOM 都已更新");
  },
  beforeDestroy() {
    console.log("beforeDestroy: 实例销毁之前,组件仍然可用");
  },
  destroyed() {
    console.log("destroyed: 实例销毁完成,组件已不可用");
  },
  errorCaptured(err, vm, info) {
    console.error("errorCaptured: 捕获来自子组件的错误");
    console.error("Error:", err);
    console.error("Component:", vm);
    console.error("Error Info:", info);
    return false; // 返回 false 可以阻止错误继续向上冒泡
  },
};
</script>

<script>
export default {
  components: {},
};
</script>

在开发过程中,我们常常会发现业务逻辑分散在各个生命周期钩子中,这种分散的代码结构有时会降低代码的可读性,尤其是当业务逻辑复杂且代码量较大时。这种情况下,代码的维护和理解成本会显著增加。

为了解决这一问题,我们可以巧妙地利用 Vue 提供的 hook: 语法来集中管理某一块的业务逻辑。通过这种方式,我们可以将相关的业务逻辑集中到一个特定的生命周期钩子中,从而让代码结构更加清晰,逻辑更加连贯,显著提升代码的可读性和可维护性。

1.this.$on("hook:mounted")用法

<template>
  <div>
    <h1>Vue 2 生命周期示例</h1>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "Hello Vue 2",
    };
  },
  created() {
    console.log("created: 实例创建完成,data 和 methods 已初始化");

    this.$on("hook:mounted", () => {
      console.log("mounted 挂载触发")
    });
    this.$on("hook:updated", () => {
      // 挂载时执行一些业务A相关逻辑;
    });
  },
};
</script>

<script>
export default {
  components: {},
};
</script>

2. @hook监听子组件生命周期

那如果我想监听一个组件的生命周期呢?其实也是可以的。

我们可以直接用@hook来监听子组件的生命周期

1.gif
<template>
  <div>
    <h1>Vue 2 生命周期示例</h1>
    <button @click="handleClick()">
      {{ show ? "销毁子组件" : "展示子组件" }}
    </button>
    <ChildComponent
      v-if="show"
      @hook:mounted="handleChildMounte"
      @hook:destroyed="handleChildDestroyed"
    />
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue";
export default {
  name: "App",
  components: {
    ChildComponent,
  },
  data() {
    return {
      show: false,
    };
  },
  methods: {
    handleClick() {
      this.show = !this.show;
    },

    handleChildMounte() {
      console.log("子组件挂载完成");
    },
    handleChildDestroyed() {
      console.log("子组件销毁完成");
    },
  },
};
</script>
<style scoped>
click-btn {
  padding: 10px 20px;
  background-color: #333;
  color: #fff;
  border: 1px solid #333;
  cursor: pointer;
}
</style>


// ChildComponent.vue
<template>
  <div>
    <h2>我是子组件</h2>
  </div>
</template>

<script>
export default {
  methods: {},
};
</script>

三、Vue3中监听生命周期

Vue3中只需要将hook替换为vue即可,我们看看代码和效果:

1.gif
<template>
  <div>
    <h1>Vue 3 生命周期示例</h1>
    <button @click="handleClick" class="click-btn">
      {{ show ? "销毁子组件" : "展示子组件" }}
    </button>
    <ChildComponent
      v-if="show"
      @vue:mounted="handleChildMounted"
      @vue:unmounted="handleChildUnmounted"
    />
  </div>
</template>

<script>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

export default {
  name: "App",
  components: {
    ChildComponent,
  },
  setup() {
    const show = ref(false);

    const handleClick = () => {
      show.value = !show.value;
    };

    const handleChildMounted = () => {
      console.log("子组件挂载完成");
    };

    const handleChildUnmounted = () => {
      console.log("子组件销毁完成");
    };

    return {
      show,
      handleClick,
      handleChildMounted,
      handleChildUnmounted,
    };
  },
};
</script>

<style scoped>
.click-btn {
  padding: 10px 20px;
  background-color: #333;
  color: #fff;
  border: 1px solid #333;
  cursor: pointer;
}
</style>

🚀🚀🚀

更多详细内容,你可以查看官方的迁移指南: Vue3迁移指南VNode 生命周期事件