Vue3组件传值

组件传值分为:父子传值跨组件传值

通信方式 适用场景 核心 API / 机制
Props 父 → 子 defineProps
Emits 子 → 父 defineEmits
v-model 父子双向绑定 modelValue + update:modelValue
Provide/Inject 祖先 → 深层后代 provide + inject
事件总线 兄弟 / 任意组件(简单场景) mitt 等第三方库
状态管理 复杂共享状态(全局 / 跨组件) Pinia/Vuex
Refs 父访问子组件实例 / DOM(谨慎用) ref + defineExpose

1. 父传子

父组件通过props将数据传递给子组件,子组件通过defineProps进行接收并使用

javascript 复制代码
父组件 Parent
┌───────────────────────────────┐
│  data: { message: "Hello Vue3" } │
│                               │
│  <Child :msg="message" />     │
└───────────────────────────────┘
           │
           ▼  (props传递)
┌───────────────────────────────┐
│  子组件 Child                 │
│                               │
│  defineProps({                │
│    msg: String                │
│  })                           │
│                               │
│  <div>{{ msg }}</div> → 显示: Hello Vue3 │
└───────────────────────────────┘

2. 子向父传值

子组件通过defineEmits定义事件,使用emit触发事件,父组件监听事件并处理数据

javascript 复制代码
子组件 Child
┌───────────────────────────────┐
│  defineEmits(['updateMsg'])   │
│                               │
│  <button @click="sendMsg">     │
│    发送消息给父组件           │
│  </button>                    │
│                               │
│  function sendMsg() {         │
│    emit('updateMsg', 'Hi Dad!')│
│  }                            │
└───────────────────────────────┘
           │
           ▼  (事件触发)
┌───────────────────────────────────────┐
│  父组件 Parent                         │
│                                       │
│  <Child @update-msg="handleUpdate" /> │
│                                       │
│  function handleUpdate(data) {        │
│    message.value = data               │
│  } → message变为: Hi Dad!             │
└───────────────────────────────────────┘
javascript 复制代码
<!-- Child.vue -->
<template>
  <div class="child">
    <h3>子组件</h3>
    <input v-model="childMsg" placeholder="输入要发送的消息" />
    <button @click="sendToParent">发送给父组件</button>
  </div>
</template>

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

const childMsg = ref('')
const emit = defineEmits(['updateMsg'])

const sendToParent = () => {
  emit('updateMsg', childMsg.value)
  childMsg.value = ''
}
</script>

<!-- Parent.vue -->
<template>
  <div class="parent">
    <h2>父组件</h2>
    <p>从子组件接收: {{ receivedMsg }}</p>
    <Child @update-msg="handleUpdate" />
  </div>
</template>

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

const receivedMsg = ref('')

const handleUpdate = (msg) => {
  receivedMsg.value = msg
}
</script>

3. 父子双向绑定

待写待更新

4. 跨组件传值:Provide/Inject

祖先组件通过provide提供数据,后代组件通过inject注入数据,实现跨层级传递

javascript 复制代码
<!-- Grandparent.vue -->
<template>
  <div class="grandparent" :class="theme">
    <h2>祖先组件</h2>
    <select v-model="theme">
      <option value="light">浅色模式</option>
      <option value="dark">深色模式</option>
    </select>
    <Parent />
  </div>
</template>

<script setup>
import { ref, provide } from 'vue'
import Parent from './Parent.vue'

const theme = ref('light')
provide('theme', theme) // 提供响应式数据
</script>

<style>
.light { background: white; color: black; }
.dark { background: #333; color: white; }
</style>

<!-- Parent.vue -->
<template>
  <div class="parent">
    <h3>父组件</h3>
    <Child />
  </div>
</template>

<script setup>
import Child from './Child.vue'
</script>

<!-- Child.vue -->
<template>
  <div class="child">
    <h4>子组件</h4>
    <p>当前主题: {{ theme }}</p>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const theme = inject('theme') // 注入响应式数据
</script>

5. 全局状态管理:Pinia

对于复杂应用使用Pinia进行管理全局状态,任何组件都可以访问和修改

javascript 复制代码
Pinia Store
┌───────────────────────────────┐
│  state: { user: null }        │
│  actions: { login, logout }   │
└───────────────────────────────┘
           │
           ▼  (组件A访问)
┌───────────────────────────────┐
│  组件A                        │
│  store.login(userInfo)        │
└───────────────────────────────┘
           │
           ▼  (组件B访问)
┌───────────────────────────────┐
│  组件B                        │
│  store.user → 获取用户信息    │
└───────────────────────────────┘
javascript 复制代码
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    user: null
  }),
  actions: {
    login(userInfo) {
      this.user = userInfo
    },
    logout() {
      this.user = null
    }
  }
})
javascript 复制代码
<!-- Login.vue -->
<template>
  <div>
    <input v-model="username" placeholder="用户名" />
    <button @click="handleLogin">登录</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useUserStore } from './stores/user'

const username = ref('')
const userStore = useUserStore()

const handleLogin = () => {
  userStore.login({ name: username.value })
}
</script>

<!-- Profile.vue -->
<template>
  <div>
    <h3>用户信息</h3>
    <p v-if="userStore.user">欢迎, {{ userStore.user.name }}</p>
    <p v-else>请先登录</p>
    <button v-if="userStore.user" @click="userStore.logout">退出</button>
  </div>
</template>

<script setup>
import { useUserStore } from './stores/user'

const userStore = useUserStore()
</script>
相关推荐
LaughingZhu5 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫5 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux6 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水7 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger7 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)7 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态7 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态7 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart7 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe57 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架