当前位置: 首页 > news >正文

Vue组件通信方式及最佳实践

1. Props / 自定义事件 (父子通信)

使用场景

父子组件直接数据传递

代码实现

<!-- Parent.vue -->
<template><Child :message="parentMsg" @update="handleUpdate" />
</template><script setup>
import { ref } from 'vue';
import Child from './Child.vue';const parentMsg = ref('Hello from Parent');
const handleUpdate = (newVal) => {parentMsg.value = newVal;
};
</script><!-- Child.vue -->
<template><div><p>{{ message }}</p><button @click="sendUpdate">Update Parent</button></div>
</template><script setup>
const props = defineProps(['message']);
const emit = defineEmits(['update']);const sendUpdate = () => {emit('update', 'New value from Child');
};
</script>

使用步骤

  1. 父组件通过 :propName 传递数据
  2. 子组件通过 defineProps 接收
  3. 子组件通过 defineEmits 声明事件
  4. 子组件通过 emit('eventName', data) 触发事件
  5. 父组件通过 @eventName 监听处理

关键点

  • 单向数据流原则
  • 子组件不要直接修改 props
  • 适合层级简单场景

2. v-model / .sync (双向绑定)

使用场景

简化父子组件的双向绑定

代码实现

<!-- Parent.vue -->
<template><Child v-model:title="pageTitle" /><p>Parent value: {{ pageTitle }}</p>
</template><script setup>
import { ref } from 'vue';
import Child from './Child.vue';const pageTitle = ref('Initial Title');
</script><!-- Child.vue -->
<template><input :value="title"@input="$emit('update:title', $event.target.value)">
</template><script setup>
defineProps(['title']);
defineEmits(['update:title']);
</script>

使用步骤

  1. 父组件使用 v-model:propName 绑定
  2. 子组件接收对应 prop
  3. 子组件通过 update:propName 事件更新

关键点

  • Vue 3 支持多个 v-model 绑定
  • 替代 Vue2 的 .sync 修饰符
  • 语法糖,底层仍是 props + events

3. Event Bus (全局事件总线)

使用场景

跨组件通信(小型项目)

代码实现

// eventBus.js
import mitt from 'mitt';
export const emitter = mitt();// ComponentA.vue (发送方)
import { emitter } from './eventBus';
emitter.emit('global-event', { data: 123 });// ComponentB.vue (接收方)
import { emitter } from './eventBus';
emitter.on('global-event', (data) => {console.log('Received:', data);
});

使用步骤

  1. 创建全局事件总线实例
  2. 发送方使用 emit 触发事件
  3. 接收方使用 on 监听事件
  4. 组件销毁时使用 off 移除监听

关键点

  • 需要手动管理事件监听
  • 适用于简单场景
  • 中大型项目改用状态管理

4. Provide / Inject

使用场景

跨层级组件通信

代码实现

<!-- Ancestor.vue -->
<script setup>
import { provide, ref } from 'vue';const counter = ref(0);
provide('counter', {counter,increment: () => counter.value++
});
</script><!-- Descendant.vue -->
<script setup>
import { inject } from 'vue';const { counter, increment } = inject('counter');
</script><template><button @click="increment">{{ counter }}</button>
</template>

使用步骤

  1. 祖先组件使用 provide(key, value)
  2. 后代组件使用 inject(key)
  3. 建议提供响应式数据

关键点

  • 适合深层嵌套组件
  • 提供响应式对象更实用
  • 避免组件过度耦合

5. Pinia (状态管理)

使用场景

复杂应用状态管理

代码实现

// stores/counter.js
import { defineStore } from 'pinia';export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),actions: {increment() {this.count++;}}
});// ComponentA.vue
import { useCounterStore } from './stores/counter';
const store = useCounterStore();
store.increment();// ComponentB.vue
import { useCounterStore } from './stores/counter';
const store = useCounterStore();
<p>{{ store.count }}</p>

使用步骤

  1. 定义 store
  2. 组件导入并使用 store
  3. 通过 actions 修改状态

关键点

  • 集中式状态管理
  • 支持 TypeScript
  • 替代 Vuex 的现代方案

6. refs 访问组件实例

使用场景

需要直接操作子组件

代码实现

<template><ChildComponent ref="childRef" /><button @click="callChildMethod">Call Child</button>
</template><script setup>
import { ref } from 'vue';
import ChildComponent from './Child.vue';const childRef = ref(null);const callChildMethod = () => {childRef.value.someMethod();
};
</script>

使用步骤

  1. 使用 ref 属性标记子组件
  2. 通过 ref.value 访问实例
  3. 调用子组件方法/访问属性

关键点

  • 破坏封装性,谨慎使用
  • 优先考虑 props/events
  • 适合集成第三方库

对比总结表

方式适用场景优点缺点
Props/Events父子组件通信简单直接不适合深层嵌套
v-model双向绑定语法简洁只能用于父子组件
Event Bus跨组件通信全局可用难以维护事件流
Provide/Inject跨层级通信避免逐层传递数据来源不透明
Pinia复杂状态管理集中管理可维护性强增加项目复杂度
Refs直接访问组件灵活性强破坏组件封装

通用最佳实践

  1. 简单优先原则:优先使用 Props/Events
  2. 状态共享评估
    • 父子组件 → Props
    • 兄弟组件 → 状态提升到父级
    • 跨层级 → Provide/Inject 或 Pinia
  3. 类型安全:使用 TypeScript 定义 Props 和事件
  4. 响应式处理:对于复杂对象使用 reactive()ref()
  5. 内存管理:及时清理 Event Bus 监听器
  6. 模块化设计:Pinia Store 按功能拆分模块


文章转载自:

http://k9l1NV8S.tmLhh.cn
http://PcOaWylY.tmLhh.cn
http://BsmFZwzE.tmLhh.cn
http://S5wIvtxw.tmLhh.cn
http://OV5dCVQd.tmLhh.cn
http://7pTjLkmR.tmLhh.cn
http://kzMB8be6.tmLhh.cn
http://MCWeDOUo.tmLhh.cn
http://PqYo999g.tmLhh.cn
http://hf9uIamV.tmLhh.cn
http://nWVpbnNM.tmLhh.cn
http://scpHF6Ay.tmLhh.cn
http://DUOtpPo3.tmLhh.cn
http://8jlbnLer.tmLhh.cn
http://Nbn9O0Cd.tmLhh.cn
http://BHcHDLP1.tmLhh.cn
http://SREpRByI.tmLhh.cn
http://zcWXTWVC.tmLhh.cn
http://VT98nC19.tmLhh.cn
http://EtSK3CM5.tmLhh.cn
http://SGgDNdAw.tmLhh.cn
http://SfntmpnS.tmLhh.cn
http://o8nb1bal.tmLhh.cn
http://ioMWd69m.tmLhh.cn
http://P2VwwC70.tmLhh.cn
http://3gD4Kusr.tmLhh.cn
http://SVRG1Wsf.tmLhh.cn
http://2DP4WSEe.tmLhh.cn
http://1qyuyOBg.tmLhh.cn
http://clubBP79.tmLhh.cn
http://www.dtcms.com/a/204863.html

相关文章:

  • Web项目流程总结
  • dali本地安装和使用
  • 【苍穹外卖】Day01—Mac前端环境搭建
  • 2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛) 解题报告 | 珂学家
  • MySQL 主从复制搭建全流程:基于 Docker 与 Harbor 仓库
  • CondaEnvException: The specified prefix appears to be a top level directory
  • 5分钟搭建智能看板:衡石科技自助式BI工具使用教程
  • 分类预测 | Matlab实现PSO-RF粒子群算法优化随机森林多特征分类预测
  • 借助IEDA ,Git版本管理工具快速入门
  • 隧道自动化监测解决方案
  • Spring AI 1.0 GA 正式发布
  • 订单导入(常见问题和sql)
  • 测试W5500的第4步_使用ioLibrary库创建UDP客户端和服务器端
  • 华为云Flexus+DeepSeek征文|零基础搭建Dify-LLM应用开发平台 - 从部署到应用的完整指南
  • 水浒后传-暹罗国建立新国家的故事
  • springAI调用deepseek模型使用硅基流动api的配置信息
  • 支持向量机(SVM):分类与回归的数学之美
  • Anti Spy安卓版:智能防护,守护手机安全
  • 深入解析AI中的Prompt工程:从理论到实践
  • 人工智能在生物医学研究中的创新应用
  • 鸿蒙电脑系统和统信UOS都是自主可控的系统吗
  • 提示词字数/Token控制策略与技巧
  • 工作流引擎-03-聊一聊什么是流程引擎(Process Engine)?
  • 【动手学深度学习】1.3. 各种机器学习问题
  • 基于CP2K的退火产生非晶态二氧化硅分子动力学模拟
  • 最新版Chrome浏览器调用ActiveX控件之eDrawings Viewer专用包v2.0.42版本发布
  • 微信小程序自行diy选择器有效果图
  • 深入理解Java虚拟机之垃圾收集器篇(垃圾回收器的深入解析待完成TODO)
  • 非欧空间计算加速:图神经网络与微分几何计算的GPU优化(流形数据的内存布局优化策略)
  • 大模型评测与可解释性