Vue 组件的生命周期钩子函数有哪些?它们在 Vue 2 和 Vue 3 中是否有变化?请详细说明每个钩子的用途。

各位观众,晚上好!欢迎来到今天的Vue.js技术讲座。我是你们的老朋友,今天咱们聊聊Vue组件生命周期这玩意儿。说实话,它就像咱们的人生一样,出生、成长、经历各种事儿、然后…嗯,结束。Vue组件也一样,有自己的生命周期。

咱们今天要聊的,主要是Vue 2和Vue 3中组件生命周期钩子函数的异同,以及它们各自的用途。别担心,我会尽量用大白话,配合代码示例,让大家彻底搞明白这玩意儿,保证你听完之后,下次面试再也不怕被问生命周期了!

一、什么是生命周期?

想象一下,你养了一盆花。你会经历:

  1. 播种/购买: 相当于组件被创建。
  2. 浇水/施肥: 相当于组件的数据初始化。
  3. 阳光照射: 相当于组件被挂载到DOM上,开始渲染。
  4. 花开花落: 相当于组件的数据变化,触发更新。
  5. 枯萎/丢弃: 相当于组件被销毁。

这就是一个简单的生命周期。Vue组件也一样,从创建到销毁,会经历一系列的阶段。而生命周期钩子函数,就是Vue提供给我们在这些特定阶段执行代码的“机会”。我们可以利用这些钩子函数,在组件的不同阶段做一些事情,比如数据初始化、发送网络请求、清理定时器等等。

二、Vue 2 的生命周期钩子

Vue 2 的生命周期钩子函数主要有以下几个:

钩子函数 用途
beforeCreate 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 简单说,这个阶段,datamethods 里的数据都还没有被初始化,你访问不到它们。 通常很少用,因为能做的操作不多。
created 实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性的计算,方法的绑定,事件的监听、订阅。 但是,$el property 尚未可用。 这个阶段可以访问到datamethods里的数据,可以进行一些数据的初始化,发送网络请求等等。 注意:这里还不能操作DOM。
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。 这个阶段,Vue 会编译模板,生成渲染函数。 虚拟DOM已经创建,但还没有挂载到真实DOM上。 通常很少用。
mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。 如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。 这个阶段,组件已经挂载到DOM上,可以进行DOM操作。 这是最常用的钩子之一。 比如,可以在这里获取DOM元素,初始化第三方库,发送异步请求等等。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。 这个钩子在数据更新之前被调用,可以进一步地更改状态,这不会触发附加的重渲染过程。 通常很少用。
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新循环。 这个阶段,可以访问到更新后的DOM。 注意:避免在此钩子中修改数据,可能导致死循环。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。 这个阶段,组件即将被销毁,可以进行一些清理工作,比如取消定时器、解绑事件监听等等。
destroyed 实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。 这个阶段,组件已经被销毁,所有的资源都已经被释放。 通常用于最后的清理工作。

让我们来看一个例子:

<template>
  <div>
    <h1>{{ message }}</h1>
    <button @click="updateMessage">更新消息</button>
    <p ref="myParagraph">这是一个段落。</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue 2!',
    };
  },
  beforeCreate() {
    console.log('beforeCreate: 组件实例创建之前');
  },
  created() {
    console.log('created: 组件实例创建完成');
    // 可以在这里发送网络请求
    // this.fetchData();
  },
  beforeMount() {
    console.log('beforeMount: 挂载之前');
  },
  mounted() {
    console.log('mounted: 组件挂载完成');
    // 可以在这里操作 DOM
    console.log('段落的innerHTML:', this.$refs.myParagraph.innerHTML);
  },
  beforeUpdate() {
    console.log('beforeUpdate: 数据更新之前');
  },
  updated() {
    console.log('updated: 数据更新完成');
  },
  beforeDestroy() {
    console.log('beforeDestroy: 组件销毁之前');
    // 可以在这里清理定时器
    // clearInterval(this.timer);
  },
  destroyed() {
    console.log('destroyed: 组件销毁完成');
  },
  methods: {
    updateMessage() {
      this.message = 'Hello Vue 2! (Updated)';
    },
  },
};
</script>

这个例子中,我们在每个生命周期钩子函数中都输出了日志。你可以在控制台中看到它们执行的顺序。

三、Vue 3 的生命周期钩子

Vue 3 的生命周期钩子函数和 Vue 2 相比,有了一些变化,主要是命名上的变化。而且Vue3中使用了Composition API后,需要从vue中引入才能使用。

Vue 2 Vue 3 用途
beforeCreate (移除) 在 Vue 3 中被移除,setup函数包含了beforeCreate和created两个钩子的逻辑。
created (移除) 在 Vue 3 中被移除,setup函数包含了beforeCreate和created两个钩子的逻辑。
beforeMount onBeforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。 这个阶段,Vue 会编译模板,生成渲染函数。 虚拟DOM已经创建,但还没有挂载到真实DOM上。 通常很少用。
mounted onMounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。 如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。 这个阶段,组件已经挂载到DOM上,可以进行DOM操作。 这是最常用的钩子之一。 比如,可以在这里获取DOM元素,初始化第三方库,发送异步请求等等。
beforeUpdate onBeforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。 这个钩子在数据更新之前被调用,可以进一步地更改状态,这不会触发附加的重渲染过程。 通常很少用。
updated onUpdated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新循环。 这个阶段,可以访问到更新后的DOM。 注意:避免在此钩子中修改数据,可能导致死循环。
beforeDestroy onBeforeUnmount 实例销毁之前调用。在这一步,实例仍然完全可用。 这个阶段,组件即将被销毁,可以进行一些清理工作,比如取消定时器、解绑事件监听等等。
destroyed onUnmounted 实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。 这个阶段,组件已经被销毁,所有的资源都已经被释放。 通常用于最后的清理工作。
onErrorCaptured 当捕获一个来自子孙组件的错误时被调用。 此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以用来优雅地处理来自子组件的错误,而不是让错误一路冒泡到应用层级。
onRenderTracked 在响应式依赖被组件的渲染函数追踪时调用。 此钩子接收一个 debugger event 作为参数。此事件会包含被追踪的响应式 property 相关的信息。
onRenderTriggered 当组件的渲染函数需要重新执行时调用。onRenderTracked 类似,此钩子也会接收一个 debugger event 对象,其中包含导致重新渲染的响应式 property 相关的信息。

Vue 3 中移除了 beforeCreatecreated 钩子, 取而代之的是 setup 函数。所有的 setup 函数都先于这些生命周期钩子执行。setup 函数是 Vue 3 中非常重要的一个概念,它提供了更大的灵活性和更好的代码组织方式。

让我们来看一个 Vue 3 的例子:

<template>
  <div>
    <h1>{{ message }}</h1>
    <button @click="updateMessage">更新消息</button>
    <p ref="myParagraph">这是一个段落。</p>
  </div>
</template>

<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue';

export default {
  setup() {
    const message = ref('Hello Vue 3!');
    const myParagraph = ref(null);

    const updateMessage = () => {
      message.value = 'Hello Vue 3! (Updated)';
    };

    onBeforeMount(() => {
      console.log('onBeforeMount: 挂载之前');
    });

    onMounted(() => {
      console.log('onMounted: 组件挂载完成');
      // 可以在这里操作 DOM
      console.log('段落的innerHTML:', myParagraph.value.innerHTML);
    });

    onBeforeUpdate(() => {
      console.log('onBeforeUpdate: 数据更新之前');
    });

    onUpdated(() => {
      console.log('onUpdated: 数据更新完成');
    });

    onBeforeUnmount(() => {
      console.log('onBeforeUnmount: 组件销毁之前');
      // 可以在这里清理定时器
      // clearInterval(timer);
    });

    onUnmounted(() => {
      console.log('onUnmounted: 组件销毁完成');
    });

    return {
      message,
      updateMessage,
      myParagraph
    };
  },
};
</script>

在这个例子中,我们使用了 Composition API,将逻辑放在了 setup 函数中。 我们用 ref 创建响应式数据,并使用 onBeforeMountonMounted 等函数来注册生命周期钩子。

四、Vue 3 的 setup 函数

setup 函数是 Vue 3 中最核心的变化之一。它是一个新的组件选项,作为在组件中使用 Composition API 的入口点。

  • setup 函数在 beforeCreate 之前执行,created 钩子被移除,他们的逻辑在setup中完成。
  • setup 函数接收两个参数:propscontext
    • props:组件接收的 props。
    • context:一个对象,包含以下属性:
      • attrs:组件的非 props attributes。
      • slots:组件的 slots。
      • emit:用于触发自定义事件。
  • setup 函数必须返回一个对象,对象中的属性将会暴露给模板。

五、错误处理钩子: onErrorCaptured (Vue 3 only)

onErrorCaptured 钩子函数用于捕获来自子组件的错误。它可以帮助你更好地处理错误,避免错误传播到整个应用。

<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script>
import { onErrorCaptured } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent,
  },
  setup() {
    onErrorCaptured((err, instance, info) => {
      console.error('捕获到错误:', err);
      console.log('组件实例:', instance);
      console.log('错误来源:', info);
      // 可以进行错误上报、降级处理等
      return false; // 阻止错误继续传播
    });

    return {};
  },
};
</script>

如果 ChildComponent 中发生了错误,onErrorCaptured 钩子函数会被调用。你可以根据错误信息进行相应的处理。 return false; 可以阻止错误继续向上传播。

六、渲染追踪钩子: onRenderTrackedonRenderTriggered (Vue 3 only)

onRenderTrackedonRenderTriggered 钩子函数主要用于调试和性能优化。

  • onRenderTracked:在响应式依赖被组件的渲染函数追踪时调用。
  • onRenderTriggered:当组件的渲染函数需要重新执行时调用。

这两个钩子函数可以帮助你了解组件的渲染过程,找出性能瓶颈。

七、总结

Vue 组件的生命周期钩子函数是理解 Vue 组件工作原理的关键。掌握这些钩子函数,可以让你更好地控制组件的行为,编写出更高效、更健壮的代码。

  • Vue 2 的生命周期钩子函数包括:beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed
  • Vue 3 的生命周期钩子函数在命名上有所变化,并且移除了 beforeCreatecreated 钩子, 取而代之的是 setup 函数。新增了onErrorCapturedonRenderTrackedonRenderTriggered
  • setup 函数是 Vue 3 中 Composition API 的入口点,提供了更大的灵活性。

记住,生命周期就像组件的人生,了解它,才能更好地“照顾”你的组件。

好了,今天的讲座就到这里。希望大家有所收获!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注