组件通信

83 阅读2分钟

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 替代

对比点propsimport/export
场景组件通信(父传子)模块复用(静态导入)
数据流向父 → 子(组件实例间)任意方向(模块级别)
运行时动态✅ 动态传值(运行时)❌ 静态导入(编译时就确定了)
使用目的组件复用 + 动态配置代码复用
会不会变可能会变(响应式)不会变(值是固定的)