Vue3 生命周期钩子(超详细)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在前端开发中,Vue3 的生命周期钩子是控制组件行为的核心工具。无论是数据初始化、DOM 操作,还是组件销毁时的资源清理,都离不开对生命周期的精准把握。对于编程初学者而言,理解这些钩子的触发顺序和使用场景,是掌握 Vue3 开发的关键一步。本文将通过 形象的比喻、代码示例和实战案例,帮助读者系统掌握 Vue3 生命周期钩子的原理与应用。


一、生命周期钩子的定义与作用

1. 什么是生命周期钩子?

生命周期钩子(Lifecycle Hooks)是 Vue3 在组件不同阶段自动触发的函数。它们如同组件的“成长轨迹”:从创建到销毁,每个阶段都有对应的钩子,开发者可以通过这些钩子在特定时刻执行自定义逻辑。

比喻

想象一个新生儿的成长过程——出生、学习走路、上学、工作、退休。每个阶段都有标志性事件,而生命周期钩子就像这些阶段中的“里程碑”,开发者可以在此时插入自己的“庆祝活动”或“任务安排”。

2. 为什么需要生命周期钩子?

  • 精准控制:在组件特定阶段执行代码(如挂载后操作 DOM)。
  • 资源管理:避免内存泄漏(如销毁时移除定时器或监听器)。
  • 状态初始化:在组件创建时加载数据或配置默认值。

二、Vue3 生命周期钩子的分类与触发顺序

Vue3 的生命周期钩子分为 选项式 API组合式 API 两种写法。下表总结了关键钩子及其触发顺序:

钩子名称阶段作用与典型用例
beforeCreate创建前极少使用,通常用组合式 API 替代
created创建后初始化数据或调用异步 API
beforeMount挂载前预处理数据(如计算属性)
mounted挂载后操作 DOM、绑定事件监听器
beforeUpdate更新前保存 DOM 状态(如滚动位置)
updated更新后操作更新后的 DOM
beforeUnmount销毁前移除监听器、清理资源
unmounted销毁后完成最后的清理工作

注意:在组合式 API 中,钩子通过 onXXX 形式调用(如 onMounted)。


三、关键钩子详解与实战案例

1. created vs mounted:数据初始化与 DOM 操作

created

在组件实例创建完成后调用,此时 模板编译未完成,无法操作 DOM。适合执行数据初始化或调用 API:

// 选项式 API
export default {
  created() {
    console.log("组件已创建,但 DOM 未挂载"); // 此时 document.querySelector("#myDiv") 会返回 null
    this.fetchData(); // 启动数据请求
  },
  methods: {
    async fetchData() {
      const response = await fetch("https://api.example.com/data");
      this.data = await response.json();
    }
  }
};

// 组合式 API
import { onMounted, onCreated } from 'vue';

export default {
  setup() {
    onCreated(() => {
      console.log("组合式 API 的 created 钩子");
      // 同步或异步操作
    });
  }
};

mounted

在组件首次渲染后调用,此时 DOM 已完全挂载,可安全操作 DOM:

// 选项式 API
mounted() {
  console.log("DOM 已就绪,可以操作了");
  this.$refs.myInput.focus(); // 通过 ref 聚焦输入框
}

// 组合式 API
onMounted(() => {
  const inputElement = document.querySelector("#myInput");
  inputElement?.focus();
});

比喻

created 是“准备好材料”,mounted 是“组装完成”——只有后者才能对“成品”进行调整。


2. beforeUpdateupdated:响应式更新的监控

这两个钩子在数据变化触发重新渲染时触发。例如,在列表更新时记录滚动位置:

// 选项式 API
export default {
  data() {
    return {
      items: [],
      scrollTop: 0
    };
  },
  beforeUpdate() {
    // 保存当前滚动位置
    this.scrollTop = document.querySelector(".list-container").scrollTop;
  },
  updated() {
    // 恢复滚动位置
    document.querySelector(".list-container").scrollTop = this.scrollTop;
  }
};

// 组合式 API
import { onBeforeUpdate, onUpdated } from 'vue';

export default {
  setup() {
    const scrollTop = ref(0);
    const listContainer = ref(null);

    onBeforeUpdate(() => {
      scrollTop.value = listContainer.value.scrollTop;
    });

    onUpdated(() => {
      listContainer.value.scrollTop = scrollTop.value;
    });

    return {
      listContainer
    };
  }
};

3. beforeUnmountunmounted:资源清理

在组件销毁前(beforeUnmount)和销毁后(unmounted)执行清理操作。例如,清除定时器或事件监听器:

// 选项式 API
data() {
  return {
    timer: null
  };
},
mounted() {
  this.timer = setInterval(this.updateTime, 1000);
},
beforeUnmount() {
  clearInterval(this.timer); // 避免内存泄漏
},

// 组合式 API
const timer = ref(null);

onMounted(() => {
  timer.value = setInterval(() => {
    // 更新时间逻辑
  }, 1000);
});

onBeforeUnmount(() => {
  clearInterval(timer.value);
});

四、常见误区与最佳实践

1. 避免在 created 中操作 DOM

由于 created 阶段 DOM 尚未生成,直接操作 DOM 会导致错误。例如:

// 错误示例:created 中操作 DOM
created() {
  const element = document.getElementById("app"); // 可能为 null
  element.style.color = "red"; // 可能引发错误
}

解决方案:将代码移至 mounted 钩子中。

2. 避免在 updated 中频繁触发副作用

updated 在每次数据变化时都会触发,若在此钩子中执行高耗计算(如遍历大数据集),可能导致性能问题。此时,优先使用 计算属性watcher

3. 组合式 API 的优先级

Vue3 推荐使用组合式 API(如 onMounted),因其:

  • 更灵活,支持解耦逻辑复用;
  • 与 TypeScript 兼容性更好。

五、实战案例:计数器组件

通过一个计数器组件,演示多个钩子的协同工作:

<template>
  <div>
    <p>当前计数:{{ count }}</p>
    <button @click="increment">+1</button>
    <button @click="reset">重置</button>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";

const count = ref(0);
let timer = null;

// 组件挂载时启动计时器
onMounted(() => {
  timer = setInterval(() => {
    count.value++;
  }, 1000);
});

// 组件销毁前清除计时器
onBeforeUnmount(() => {
  clearInterval(timer);
});

const increment = () => {
  count.value++;
};

const reset = () => {
  count.value = 0;
};
</script>

功能说明

  • onMounted 启动每秒自增计时器;
  • onBeforeUnmount 清除计时器,防止内存泄漏;
  • 用户手动点击按钮时,count 更新会触发视图响应式渲染。

六、总结与进阶方向

通过本文,读者应掌握 Vue3 生命周期钩子的核心概念、触发顺序及典型用例。关键要点总结如下:

  1. 钩子分类:创建、挂载、更新、销毁四大阶段;
  2. 核心钩子created/mounted 处理数据与 DOM,beforeUnmount 清理资源;
  3. 组合式 API 是未来开发趋势,需优先掌握。

进阶方向

  • 学习 watchwatchEffect 实现动态响应;
  • 结合 Vue3 的 Suspense 组件处理异步加载;
  • 通过性能分析工具(如 Vue DevTools)观察生命周期触发细节。

掌握生命周期钩子,是 Vue3 开发者从“会用”到“精通”的必经之路。希望本文能帮助读者在实际项目中更高效、安全地控制组件行为!

最新发布