本文最后更新于 46 天前,其中的信息可能已经有所发展或是发生改变。
企业级解决方案|完整代码示例|最佳实践指南
📦 核心通信模式
1. Props/Events 基础通信
<!-- Parent.vue -->
<template>
<Child :message="msg" @update="handleUpdate"/>
</template>
<!-- Child.vue -->
<script setup>
defineProps({ message: String })
const emit = defineEmits(['update'])
emit('update', 'new value')
</script>
🔔 适用场景:父子组件简单数据传递
2. 增强型 v-model
<!-- Parent.vue -->
<UserForm v-model:name="form.name"/>
<!-- UserForm.vue -->
<script setup>
defineProps(['name'])
defineEmits(['update:name'])
</script>
🌟 优势:支持多个双向绑定参数
3. 模板引用
<template>
<VideoPlayer ref="player"/>
</template>
<script setup>
const player = ref()
// 调用子组件暴露的方法
player.value.play()
// 子组件暴露方法
defineExpose({
play: () => {
/* 播放逻辑 */
}
})
</script>
⚠️ 注意:避免过度依赖组件实例方法
🌐 全局通信方案
4. 依赖注入
// 祖先组件
<script setup>
const theme = reactive({ color: 'blue' })
provide('theme', readonly(theme))
</script>
// 后代组件
<script setup>
const theme = inject('theme')
</script>
🔧 最佳实践:使用 readonly
防止意外修改
5. Pinia 状态管理
// stores/counter.ts
export const useCounter = defineStore('counter', () => {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
})
// 组件使用
<script setup>
const counter = useCounter()
counter.increment()
</script>
📊 数据流:适合中大型应用状态管理
6. 事件总线
// utils/event.ts
import mitt from 'mitt'
export const emitter = mitt()
// 组件A
emitter.emit('toast', '操作成功')
// 组件B
emitter.on('toast', msg => console.log(msg))
🚨 注意:需在组件卸载时移除监听
🛠️ 高级模式
7. 属性透传
<template>
<BaseInput v-bind="$attrs"/>
</template>
<script setup>
// 底层组件
defineProps(['modelValue'])
</script>
💡 技巧:配合 inheritAttrs: false
使用
8. 作用域插槽
<!-- 使用 -->
<DataTable #row="{ item }">
<td>{{ item.name }}</td>
</DataTable>
<!-- 实现 -->
<tr v-for="item in items">
<slot name="row" :item="item"/>
</tr>
🎨 适用场景:高度可定制的UI组件
🔗 路由与存储
9. 路由参数
<script setup>
const route = useRoute()
const id = computed(() => route.params.id)
router.push({ name: 'user', params: { id: 1 } })
</script>
🌐 最佳实践:使用路由守卫管理参数验证
10. 组合式函数
// utils/useMouse.ts
export function useMouse() {
const x = ref(0)
onMounted(() =>
window.addEventListener('mousemove', e => x.value = e.x)
)
return { x }
}
// 使用
const { x } = useMouse()
🧩 优势:逻辑复用与解耦
11. Web存储
// utils/storage.ts
export function useSyncStorage(key: string, value: any) {
const data = ref(JSON.parse(localStorage.getItem(key)) || value)
watch(data, val =>
localStorage.setItem(key, JSON.stringify(val))
)
return data
}
// 使用
const settings = useSyncStorage('settings', { theme: 'light' })
🔐 安全增强:建议添加数据加密
📋 方案选型表
场景 | 推荐方案 | 代码示例 | 优势 |
---|---|---|---|
父子组件通信 | Props/Events | defineProps + defineEmits |
简单直接 |
跨层级状态共享 | Provide/Inject | provide + inject |
解决嵌套传递问题 |
全局状态管理 | Pinia | defineStore + useStore |
类型安全/可维护性 |
组件方法调用 | 模板引用 | ref.value.method() |
直接访问实例 |
非父子组件通信 | 事件总线 | emitter.emit /on |
灵活解耦 |
页面状态持久化 | 路由参数 | route.params |
URL可分享 |
🚀 企业级实践
// 严格类型约束
defineProps<{
id: number
items: Array<{ name: string }>
}>()
// 安全事件总线
type Events = {
login: { userId: number }
error: string
}
const emitter = mitt<Events>()
// 防抖函数
export function useDebounce(fn: Function, delay: number) {
let timer: number
return (...args: any[]) => {
clearTimeout(timer)
timer = setTimeout(() => fn(...args), delay)
}
}
📚 扩展阅读推荐
▶️ Vue3组件基础
▶️ Vue3 Provide/Inject API
▶️ Pinia 官方文档
▶️ Mitt GitHub 仓库
▶️ Vue3 组合式API指南
▶️ 使用Vue3和Composition API管理Web存储