技术文档中心
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
  • Vue2 基础

    • Vue 学习指南
    • Vue2 快速入门
    • Vue2 模板语法
    • Vue2 组件基础
    • Vue2 计算属性与侦听器
    • Vue2 生命周期
  • Vue2 进阶

    • Vue2 组件通信
    • Vue2 插槽详解
    • Vue2 混入与自定义指令
    • Vue2 过渡与动画
    • Vuex 状态管理
  • Vue2 高级

    • Vue2 性能优化
    • Vue2 服务端渲染(SSR)
    • Vue2 源码解析
  • Vue3 基础

    • Vue3 快速入门
    • Vue3 Composition API
    • Vue3 响应式系统
    • Vue3 组件基础
    • Vue3 生命周期
  • Vue3 进阶

    • Vue3 组合式函数
    • Vue3 组件通信
    • Vue3 Teleport 与 Suspense
    • Pinia 状态管理
    • Vue Router 4
  • Vue3 高级

    • Vue3 TypeScript
    • Vue3 性能优化
    • Vue3 测试
    • Vue3 SSR
    • Vue3 源码解析
  • 实战项目

    • Vue2 实战项目
    • Vue3 实战项目
    • Vue2 迁移 Vue3

Vue3 组件通信

Props / Emits

父传子(Props)

<!-- 父组件 -->
<template>
  <ChildComponent :message="parentMessage" />
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const parentMessage = ref('Hello from parent')
</script>

<!-- 子组件 -->
<script setup>
defineProps({
  message: String
})
</script>

子传父(Emits)

<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update'])

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

<!-- 父组件 -->
<template>
  <ChildComponent @update="handleUpdate" />
</template>

<script setup>
const handleUpdate = (payload) => {
  console.log(payload)
}
</script>

v-model

单个 v-model

<!-- 子组件 -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<!-- 父组件 -->
<template>
  <ChildComponent v-model="text" />
</template>

多个 v-model

<!-- 子组件 -->
<script setup>
defineProps(['firstName', 'lastName'])
defineEmits(['update:firstName', 'update:lastName'])
</script>

<!-- 父组件 -->
<template>
  <ChildComponent
    v-model:first-name="first"
    v-model:last-name="last"
  />
</template>

provide / inject

<!-- 父组件 -->
<script setup>
import { provide, ref } from 'vue'

const theme = ref('dark')
provide('theme', theme)

// 提供响应式数据
const updateTheme = (newTheme) => {
  theme.value = newTheme
}
provide('updateTheme', updateTheme)
</script>

<!-- 子孙组件 -->
<script setup>
import { inject } from 'vue'

const theme = inject('theme')
const updateTheme = inject('updateTheme')
</script>

提供默认值

const theme = inject('theme', 'light')

使用 Symbol

// keys.js
export const themeKey = Symbol()

// 父组件
import { themeKey } from './keys'
provide(themeKey, theme)

// 子组件
import { themeKey } from './keys'
const theme = inject(themeKey)

Refs

模板引用

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

const childRef = ref(null)

onMounted(() => {
  childRef.value.someMethod()
})
</script>

<template>
  <ChildComponent ref="childRef" />
</template>

defineExpose

<!-- 子组件 -->
<script setup>
import { ref } from 'vue'

const count = ref(0)
const increment = () => count.value++

// 显式暴露
defineExpose({
  count,
  increment
})
</script>

EventBus(不推荐)

Vue3 移除了 $on、$off 等方法,推荐使用第三方库如 mitt。

yarn add mitt
// eventBus.js
import mitt from 'mitt'
export const emitter = mitt()

// 组件 A
import { emitter } from './eventBus'
emitter.emit('event-name', data)

// 组件 B
import { emitter } from './eventBus'
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  emitter.on('event-name', handleEvent)
})

onUnmounted(() => {
  emitter.off('event-name', handleEvent)
})

Pinia

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  }
})

// 组件中使用
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
counter.increment()
最近更新: 2026/1/27 15:51
Contributors: hailong
Prev
Vue3 组合式函数
Next
Vue3 Teleport 与 Suspense