Vue 组件通信详解

Vue 组件通信详解

组件通信的重要性

在 Vue 应用中,组件通信是一个核心概念,良好的组件通信机制可以让应用更容易维护和扩展。

Props 父子组件通信

父组件传递数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 父组件 -->
<template>
<child-component
:message="message"
:user="user"
/>
</template>

<script setup>
import { ref, reactive } from 'vue'

const message = ref('Hello from parent')
const user = reactive({
name: 'John',
age: 25
})
</script>

子组件接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 子组件 -->
<template>
<div>
<p>{{ message }}</p>
<p>{{ user.name }}</p>
</div>
</template>

<script setup>
defineProps({
message: String,
user: Object
})
</script>

Emits 子父组件通信

子组件触发事件

1
2
3
4
5
6
7
8
9
10
11
<template>
<button @click="handleClick">Click Me</button>
</template>

<script setup>
const emit = defineEmits(['update', 'delete'])

const handleClick = () => {
emit('update', { id: 1, data: 'new data' })
}
</script>

父组件监听事件

1
2
3
4
5
6
<template>
<child-component
@update="handleUpdate"
@delete="handleDelete"
/>
</template>

依赖注入 Provide/Inject

父组件提供数据

1
2
3
4
5
6
<script setup>
import { provide, ref } from 'vue'

const theme = ref('dark')
provide('theme', theme)
</script>

子组件注入数据

1
2
3
4
5
<script setup>
import { inject } from 'vue'

const theme = inject('theme', 'light') // 第二个参数是默认值
</script>

事件总线

虽然 Vue 3 移除了全局事件总线,但我们可以使用 mitt 库实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
// eventBus.js
import mitt from 'mitt'
export default mitt()

// 组件 A
import eventBus from './eventBus'
eventBus.emit('custom-event', { data: 'hello' })

// 组件 B
import eventBus from './eventBus'
eventBus.on('custom-event', (data) => {
console.log(data)
})

Vuex/Pinia 状态管理

对于大型应用,推荐使用状态管理库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Pinia 示例
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
state: () => ({
name: 'John',
isAdmin: false
}),
actions: {
updateName(name) {
this.name = name
}
}
})

最佳实践建议

  1. 优先使用 props 和 emits 进行父子组件通信
  2. 对于深层组件通信,考虑使用依赖注入
  3. 复杂状态管理场景,使用 Pinia
  4. 避免过度使用全局状态
  5. 保持数据流的可预测性

提示:选择合适的通信方式对于构建可维护的 Vue 应用至关重要。根据具体场景选择最适合的通信方式。