元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
Vue3 基础
▶
环境搭建
安装与配置
项目创建
开发工具
▶
模板语法
插值表达式
指令系统
事件处理
▶
核心概念
▶
响应式系统
ref与reactive
计算属性
侦听器
▶
组合式API
setup函数
生命周期钩子
自定义Hooks
▶
组件开发
▶
组件基础
组件通信
Props详解
插槽机制
▶
高级组件
动态组件
异步组件
递归组件
▶
状态管理
▶
Vuex基础
状态存储
模块化
组合式写法
▶
Pinia
创建Store
状态操作
插件机制
发布时间:
2025-03-22 12:15
↑
☰
# Vue3 组件通信详解 本文将详细介绍Vue3中组件间通信的各种方式,包括Props/Emit、Provide/Inject、事件总线等方法的使用和最佳实践。 ## Props和Emit ### 1. Props传递数据 ```vue <template> <div> <child-component :message="message" :user="user" :items="items" @update="handleUpdate" /> </div> </template> <script setup> import { ref, reactive } from 'vue' import ChildComponent from './ChildComponent.vue' // 父组件数据 const message = ref('Hello from parent') const user = reactive({ name: 'John', age: 30 }) const items = ref(['item1', 'item2', 'item3']) // 处理子组件事件 const handleUpdate = (newValue) => { console.log('Updated:', newValue) } </script> ``` 子组件: ```vue <template> <div> <p>Message: {{ message }}</p> <p>User: {{ user.name }}, {{ user.age }}</p> <ul> <li v-for="item in items" :key="item">{{ item }}</li> </ul> <button @click="updateParent">Update</button> </div> </template> <script setup> import { defineProps, defineEmits } from 'vue' // 定义props const props = defineProps({ message: { type: String, required: true }, user: { type: Object, required: true }, items: { type: Array, default: () => [] } }) // 定义emit事件 const emit = defineEmits(['update']) const updateParent = () => { emit('update', 'New Value') } </script> ``` ### 2. v-model使用 ```vue <!-- 父组件 --> <template> <div> <custom-input v-model="text" v-model:title="title" /> </div> </template> <script setup> import { ref } from 'vue' const text = ref('') const title = ref('') </script> <!-- 子组件 --> <template> <div> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> <input :value="title" @input="$emit('update:title', $event.target.value)" /> </div> </template> <script setup> defineProps(['modelValue', 'title']) defineEmits(['update:modelValue', 'update:title']) </script> ``` ## Provide/Inject ### 1. 基础用法 ```vue <!-- 父组件 --> <template> <div> <child-component /> </div> </template> <script setup> import { provide, ref } from 'vue' // 提供响应式数据 const theme = ref('light') const updateTheme = (value) => { theme.value = value } provide('theme', theme) provide('updateTheme', updateTheme) </script> <!-- 子组件或更深层组件 --> <template> <div :class="theme"> <button @click="toggleTheme"> Toggle Theme </button> </div> </template> <script setup> import { inject } from 'vue' const theme = inject('theme') const updateTheme = inject('updateTheme') const toggleTheme = () => { updateTheme(theme.value === 'light' ? 'dark' : 'light') } </script> ``` ### 2. 使用Symbol作为key ```javascript // constants.js export const themeSymbol = Symbol('theme') export const userSymbol = Symbol('user') ``` ```vue <!-- 父组件 --> <script setup> import { provide, reactive } from 'vue' import { themeSymbol, userSymbol } from './constants' const theme = reactive({ mode: 'light', color: '#ffffff' }) const user = reactive({ name: 'John', role: 'admin' }) provide(themeSymbol, theme) provide(userSymbol, user) </script> <!-- 子组件 --> <script setup> import { inject } from 'vue' import { themeSymbol, userSymbol } from './constants' const theme = inject(themeSymbol) const user = inject(userSymbol) </script> ``` ## 事件总线 ### 1. 创建事件总线 ```javascript // eventBus.js import mitt from 'mitt' const emitter = mitt() export default emitter ``` ### 2. 使用事件总线 ```vue <!-- 组件A --> <script setup> import { onMounted, onUnmounted } from 'vue' import emitter from './eventBus' // 发送事件 const sendMessage = () => { emitter.emit('custom-event', { message: 'Hello from Component A', timestamp: Date.now() }) } // 监听事件 const handleEvent = (data) => { console.log('Received in A:', data) } onMounted(() => { emitter.on('response-event', handleEvent) }) onUnmounted(() => { emitter.off('response-event', handleEvent) }) </script> <!-- 组件B --> <script setup> import { onMounted, onUnmounted } from 'vue' import emitter from './eventBus' // 监听事件 const handleEvent = (data) => { console.log('Received in B:', data) // 发送响应 emitter.emit('response-event', { message: 'Hello from Component B', timestamp: Date.now() }) } onMounted(() => { emitter.on('custom-event', handleEvent) }) onUnmounted(() => { emitter.off('custom-event', handleEvent) }) </script> ``` ## 状态管理工具 ### 1. Pinia ```javascript // stores/counter.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, history: [] }), getters: { doubleCount: (state) => state.count * 2 }, actions: { increment() { this.count++ this.history.push(this.count) } } }) ``` 使用示例: ```vue <!-- 组件A --> <script setup> import { useCounterStore } from '@/stores/counter' const counter = useCounterStore() const increment = () => { counter.increment() } </script> <!-- 组件B --> <script setup> import { storeToRefs } from 'pinia' import { useCounterStore } from '@/stores/counter' const counter = useCounterStore() const { count, doubleCount } = storeToRefs(counter) </script> ``` ## 最佳实践 ### 1. 选择合适的通信方式 ```javascript // 1. Props/Emit:父子组件通信 const props = defineProps(['value']) const emit = defineEmits(['update']) // 2. Provide/Inject:跨多级组件共享数据 const theme = inject('theme', 'light') // 提供默认值 // 3. 事件总线:非关联组件通信 emitter.emit('event', data) // 4. 状态管理:全局状态管理 const store = useStore() ``` ### 2. 类型支持 ```typescript // 使用TypeScript定义Props类型 interface Props { message: string user: { name: string age: number } callback?: (value: string) => void } const props = defineProps<Props>() // 定义Emit类型 interface Emits { (e: 'update', value: string): void (e: 'delete', id: number): void } const emit = defineEmits<Emits>() ``` ### 3. 性能优化 ```vue <script setup> import { shallowRef, markRaw } from 'vue' // 使用shallowRef优化大数据 const bigData = shallowRef(new Array(1000)) // 使用markRaw标记不需要响应式的数据 const staticData = markRaw({ // 静态配置数据 }) // 使用computed缓存计算结果 const filteredList = computed(() => { return list.value.filter(item => item.active) }) </script> ``` ## 总结 本文详细介绍了Vue3中的组件通信方式: 1. Props/Emit - 父子组件数据传递 - v-model使用 - 类型支持 2. Provide/Inject - 跨级组件通信 - 响应式数据共享 - Symbol key使用 3. 事件总线 - mitt实现 - 事件监听和清理 - 组件间解耦 4. 状态管理 - Pinia使用 - 状态共享 - 性能优化 通过合理使用这些通信方式,可以构建出结构清晰、易于维护的Vue3应用。建议根据具体场景选择最适合的通信方式,并注意遵循最佳实践来优化性能和提高代码质量。