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>
相关推荐
Mike_jia4 分钟前
OpenDeRisk:AI 原生风险智能系统 ——7*24H 应用系统AI数字运维助手(AI-SRE)
前端
朱穆朗13 分钟前
electron升级到33.0.x版本后,devtools字体的修改方法
前端·javascript·electron
2501_9444522319 分钟前
智能洞察 Cordova 与 OpenHarmony 混合开发实战
javascript
IT_陈寒21 分钟前
Java 21新特性实战:5个必学的性能优化技巧让你的应用提速40%
前端·人工智能·后端
Irene199125 分钟前
insertAdjacentHTML() 详解
javascript·dom
HarrySunCn26 分钟前
大夏龙雀DX-CT511N-B实战之路-第1步
前端·单片机·物联网·iot
未来之窗软件服务34 分钟前
幽冥大陆(七十七)C# 调用 中文huayan-medium.onnx —东方仙盟练气期
前端·ui·c#·仙盟创梦ide·东方仙盟
古茗前端团队35 分钟前
用 NAudio 做一个音频播放器及原理
前端
成为大佬先秃头37 分钟前
渐进式JavaScript框架:Vue 工具 & 模块化 & 迁移
开发语言·javascript·vue.js
xiaoxue..38 分钟前
二叉搜索树 BST 三板斧:查、插、删的底层逻辑
javascript·数据结构·算法·面试