vue组件通信方式概览
方式 | 方向 | 说明 |
---|---|---|
1. props | 父传子 | 最常用、最推荐,父组件传数据给子组件 |
2. emit | 子传父 | 子组件触发事件,把数据传回给父组件 |
3. v-model | 双向绑定 | 父子组件之间的数据同步(语法糖) |
4. provide/inject | 跨层传递 | 祖先组件向后代组件传值,中间不管多少层 |
5. 全局状态管理(如 Pinia) | 任意组件间 | 适用于跨页面、跨组件的共享状态 |
6. 事件总线(已不推荐) | 任意组件间 | 以前用得多,现在用 Vuex / Pinia 代替了 |
props:父传子(最常用)
父组件把数据传给子组件:
<!-- 父组件 -->
<HelloWorld msg="Hello World" />
<!-- 子组件 HelloWorld.vue -->
<script setup>
const props = defineProps({
msg: String
})
</script>
<template>
<div>{{ msg }}</div>
</template>
emit:子传父(事件机制)
子组件告诉父组件“我完成了一件事”:
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['sayHello'])
function onClick() {
emit('sayHello', '你好,父组件')
}
</script>
<template>
<button @click="onClick">打招呼</button>
</template>
<!-- 父组件 -->
<Child @sayHello="handleSayHello" />
<script setup>
function handleSayHello(msg) {
console.log('子组件说:', msg)
}
</script>
v-model:父子双向绑定(语法糖)
<!-- 父组件 -->
<MyInput v-model="name" />
<!-- 子组件 MyInput.vue -->
<script setup>
const modelValue = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input :value="modelValue" @input="e => emit('update:modelValue', e.target.value)" />
</template>
这其实是父组件用 value
传给子组件,子组件用 update:modelValue
发回去,Vue 自动把这套组合成 v-model
。
provide / inject
:跨层传值(不经过中间组件)
<!-- 祖先组件 -->
<script setup>
provide('themeColor', 'blue')
</script>
<!-- 子孙组件 -->
<script setup>
const themeColor = inject('themeColor')
</script>
祖先组件调用 provide
,后代组件用 inject
就能拿到。
状态管理
适合多个组件都需要共享的状态,比如用户信息、权限、购物车数据等。
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: 'abc'
})
})
<script setup>
import { useUserStore } from '@/stores/user'
const user = useUserStore()
</script>
<template>
<div>{{ user.name }}</div>
</template>
props
在 Vue 中,props
是 父组件传值给子组件 的机制。你可以理解成“父亲交代给孩子的任务”。
例如:
<!-- 父组件模板 -->
<SideBar mode="horizontal" />
这个时候 SideBar.vue
就会通过 defineProps
来接收这个 mode
:
const props = defineProps({
mode: {
type: String,
default: 'vertical'
}
})
这样子组件内部就可以通过 props.mode
使用这个值了。
和子组件向父组件传值的对比
-
父传子:props
-
子传父:emit 事件
emit('updateSomething', value)
父组件监听:
<Child @updateSomething="handleUpdate" />
方向 | 方式 | 说明 |
---|---|---|
父 ➡ 子 | props | 父组件传值给子组件 |
子 ➡ 父 | emit 事件 | 子组件触发事件给父组件 |
为什么 props
不能用 import/export
替代
对比点 | props | import/export |
---|---|---|
场景 | 组件通信(父传子) | 模块复用(静态导入) |
数据流向 | 父 → 子(组件实例间) | 任意方向(模块级别) |
运行时动态 | ✅ 动态传值(运行时) | ❌ 静态导入(编译时就确定了) |
使用目的 | 组件复用 + 动态配置 | 代码复用 |
会不会变 | 可能会变(响应式) | 不会变(值是固定的) |