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>
相关推荐
随风一样自由2 小时前
React中实现iframe嵌套登录页面:跨域与状态同步解决方案详解
前端·react.js·前端框架·跨域
测试人社区—52722 小时前
破茧成蝶:DevOps流水线测试环节的效能跃迁之路
运维·前端·人工智能·git·测试工具·自动化·devops
_菜鸟果果2 小时前
vue-amap高德地图绘制线路轨迹
前端·vue.js·elementui
一个处女座的程序猿O(∩_∩)O2 小时前
React Native vs React Web:深度对比与架构解析
前端·react native·react.js
n***i952 小时前
前端技术的下一场进化:从工程化走向智能化的全面重构
前端·重构
@大迁世界2 小时前
紧急:React 19 和 Next.js 的 React 服务器组件存在关键漏洞
服务器·前端·javascript·react.js·前端框架
晓得迷路了2 小时前
栗子前端技术周刊第 109 期 - Vite 8 Beta、JavaScript 三十周年、Prettier 3.7...
前端·javascript·vite
Terry_Tsang2 小时前
ceph mon 报错 full ratio(s) out of order 解决方法
服务器·前端·ceph
别叫我->学废了->lol在线等2 小时前
自然语言转成formily+shadcn组件的jsonschema
javascript·json