Vue3 组件开发:生命周期钩子,组件之间通信全方案

一、生命周期钩子(组合式 API)

1.1 钩子总览

组合式钩子 对应选项式 触发时机 典型业务
onBeforeMount beforeMount 挂载前 极少用
onMounted mounted 挂载完成,DOM 可访问 操作 DOM、初始化图表
onBeforeUpdate beforeUpdate 数据变化、DOM 更新前 更新前处理
onUpdated updated DOM 更新后 依赖 DOM 的操作(慎用)
onBeforeUnmount beforeDestroy 卸载前 清理定时器、解绑事件
onUnmounted destroyed 卸载后 收尾

关键变化 :组合式 API 没有 beforeCreate / created ------setup 本身就在创建阶段执行,作用等同二者。钩子必须在 setup 顶层同步调用。

vue 复制代码
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";

const list = ref([]);
let timer: number | undefined;

onMounted(async () => {
  list.value = await fetchList();        // 请求数据
  timer = setInterval(() => {}, 1000);   // 启动定时器
});

onBeforeUnmount(() => {
  clearInterval(timer);                  // 必须清理,防内存泄漏
});
</script>

记忆口诀:onMounted 动 DOM 拉数据、onBeforeUnmount 清资源keep-alive 缓存组件还有 onActivated / onDeactivated


二、父传子:props

2.1 defineProps 声明与类型校验

vue 复制代码
<!-- 子组件 Child.vue -->
<script setup lang="ts">
// 类型声明(编译期校验 + IDE 提示)
interface User {
  name: string;
  age: number;
}

// 方式一:纯 TS 类型
const props = defineProps<{
  title: string;
  user: User;
  count?: number;              // 可选
}>();

// 方式二:运行时校验 + 默认值(withDefaults)
const props2 = withDefaults(
  defineProps<{ count?: number; list: string[] }>(),
  {
    count: 0,
    list: () => [],            // 对象/数组默认值用函数返回
  }
);
</script>

<template>
  <h3>{{ title }}</h3>
  <p>{{ user.name }}</p>
</template>
vue 复制代码
<!-- 父组件 -->
<child title="标题" :user="userInfo" :count="5" />

2.2 单向数据流

props 是只读的 ,子组件不能修改(修改会告警且不生效)。要派生值用 computed,要改父数据用 $emit / defineModel


三、子传父:defineEmits 自定义事件

vue 复制代码
<!-- 子组件 -->
<script setup lang="ts">
const emit = defineEmits<{
  change: [value: number];                    // 事件名 + 参数类型
  submit: [payload: { name: string }];
}>();

function handleClick() {
  emit("change", 42);                          // 触发事件并传参
}
</script>

<template>
  <button @click="handleClick">上报</button>
</template>
vue 复制代码
<!-- 父组件 -->
<script setup lang="ts">
function handleChange(val: number) {
  console.log("子组件上报:", val);
}
</script>

<template>
  <child @change="handleChange" />
</template>

四、组件双向绑定 defineModel(Vue 3.4+)

4.1 基本用法

vue 复制代码
<!-- 子组件:可双向绑定的输入框 -->
<script setup lang="ts">
const model = defineModel<string>();       // 声明双向绑定值

function clear() {
  model.value = "";
}
</script>

<template>
  <input v-model="model" placeholder="输入内容" />
</template>
vue 复制代码
<!-- 父组件 -->
<script setup lang="ts">
import { ref } from "vue";
const keyword = ref("");
</script>

<template>
  <my-input v-model="keyword" />
</template>

4.2 多个 v-model 与默认值

ts 复制代码
const visible = defineModel<boolean>("visible", { default: false });  // v-model:visible
const title = defineModel<string>("title");                            // v-model:title

底层等价于 modelValue + update:modelValue(或具名 xxx + update:xxx),Vue 3.4 起用 defineModel 一行搞定。


五、跨层级 provide / inject

解决祖先 → 任意后代的通信,免去逐层传 props。

ts 复制代码
// 祖先组件
import { ref, provide } from "vue";

const theme = ref("light");
const updateTheme = (val: string) => (theme.value = val);

provide("theme", theme);          // 提供响应式数据
provide("updateTheme", updateTheme);   // 提供修改函数(避免后代直接改)
ts 复制代码
// 后代组件(任意层级)
import { inject } from "vue";

const theme = inject<Ref<string>>("theme", ref("light"));   // 第二个参数是默认值
const updateTheme = inject<(v: string) => void>("updateTheme", () => {});
要点 说明
响应式 提供 ref(或 reactive + toRefs),不要提供普通值(会失去响应)
修改方式 同时 provide 修改函数,遵循单向数据流
键冲突 用 Symbol 或字符串常量统一管理

六、踩坑:props 只读、类型校验失效

现象 解决
直接修改 props 告警 + 修改不生效 computed 派生 / defineModel / emit
props 类型校验"失效" 运行时无报错(TS 类型是编译期) 需要运行时校验用 withDefaults + 自定义 validator,或 defineProps 对象写法
defineModel 不生效 报"没有此宏" 升级 Vue 到 3.4+
provide 普通值 后代修改不同步 提供 ref 并传修改函数
inject 拿不到 父级未 provide 或键不一致 检查键名 + 提供默认值兜底
emit 事件名大小写 @myEventmy-event 不匹配 统一用 kebab-case(my-event

七、总结

  • 生命周期:6 个组合式钩子,setup 取代 beforeCreate/created,卸载前必清理;
  • 父传子defineProps + TS 类型 / withDefaults 默认值,只读单向流;
  • 子传父defineEmits 类型化声明 + $emit 传参;
  • 双向绑定defineModel(3.4+)一行实现,支持多个与默认值;
  • 跨层provide + inject(传 ref + 修改函数,保持单向流);
  • 踩坑:props 只读、运行时校验、3.4 版本要求、事件命名 kebab-case。
相关推荐
雪芽蓝域zzs1 小时前
分页组件 + el-config-provider 中文国际化 + 靠右布局
前端·javascript·vue.js
恋猫de小郭2 小时前
iPhone Duo 适配详解,需要改变的不止是布局模型
前端·flutter·ios
萧行之2 小时前
Observable Plot 源码深度解析——4 核心抽象逐项学习
前端·学习·数据可视化
今日无bug2 小时前
为什么大模型回答总是一个字一个字蹦出来?聊聊 SSE 流式输出与 BFF 层的那些事
前端·llm
志尊宝2 小时前
Vue3 零基础每日笔记(016):v-for 列表渲染——key 的作用与为什么不能用 index
javascript·vue.js·笔记
CIO_Alliance2 小时前
AI微调系列(1)| 全量微调、LoRA、QLoRA 三种方案怎么选
前端·人工智能·神经网络·机器学习·embedding·企业ai转型
hanbo17C22 小时前
企业官网能不能看出公司实力?选建站公司前,先看这6条硬标准
运维·服务器·前端
zzzll11112 小时前
LLM 学习第 24 课:Agent Harness
前端·人工智能·学习
Bmob后端云2 小时前
Bmob后端云实战|Python实现SSE流式输出,给备忘录AI加上打字机效果
前端·github