vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3组件传参方式大全

Vue3中常见的组件传参方式大全及对比详解

作者:AI砖家

本文详细解析了Vue3中多种数据传递与通信方式,包括props/emits、v-model、provide/inject、ref、Pinia/Vex、组合式函数等,并对比了它们各自的优缺点及适用场景,帮助开发者根据实际需求选择最合适的方案,需要的朋友可以参考下

在 Vue3 的日常开发中,组件间的数据传递与通信是最基本的操作。面对不同的组件关系(父子、祖孙、兄弟、任意组件)和不同的交互需求(单向、双向、共享状态、跨层级透传),Vue3 提供了丰富而灵活的传参方案。本文将对 Vue3 中常见的传参方式进行系统梳理,对比它们的特性和适用场景,帮助你根据实际情况做出最合适的选择。

一、父子组件通信

1. Props —— 父传子

父组件通过自定义属性向子组件传递数据,子组件用 defineProps 声明接收。

<!-- 父组件 -->
<Child :title="pageTitle" :count="10" />
<!-- 子组件 -->
<script setup>
const props = defineProps({
  title: String,
  count: Number
})
</script>
<template>
  <h1>{{ props.title }}</h1>
</template>

2. Emits —— 子传父

子组件通过 defineEmits 声明事件,触发时将数据作为参数回传给父组件。

<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update', 'delete'])
function handleClick() {
  emit('update', { id: 1, value: 'new' })
}
</script>
<!-- 父组件 -->
<Child @update="handleUpdate" />

3. v-model —— 双向绑定

Vue3 支持多个 v-model 绑定,本质是 prop + emit 的语法糖。子组件通过 defineProps 接收 modelValue,通过 defineEmits 触发 update:modelValue

<!-- 父组件 -->
<CustomInput v-model="text" v-model:visible="show" />
<!-- 子组件 -->
<script setup>
const props = defineProps({
  modelValue: String,
  visible: Boolean
})
const emit = defineEmits(['update:modelValue', 'update:visible'])
function updateValue(e) {
  emit('update:modelValue', e.target.value)
}
</script>

4. Ref +defineExpose—— 父组件直接访问子组件

父组件通过 ref 获取子组件实例,子组件通过 defineExpose 暴露方法和数据。

<!-- 父组件 -->
<script setup>
import { ref } from 'vue'
const childRef = ref(null)
function focusInput() {
  childRef.value?.focus()
}
</script>
<template>
  <Child ref="childRef" />
</template>
<!-- 子组件 -->
<script setup>
import { ref } from 'vue'
const inputRef = ref(null)
function focus() {
  inputRef.value?.focus()
}
defineExpose({ focus })
</script>

二、祖孙 / 跨层级通信

5. provide / inject —— 依赖注入

祖先组件通过 provide 提供数据,任意后代组件通过 inject 接收。

<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
provide('theme', theme)
</script>
<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme', 'light') // 可设默认值
</script>

6. 透传 Attributes ($attrs)

父组件传递给子组件、但子组件未声明为 props 的属性,会被自动透传到子组件的根元素上。可通过 useAttrs() 获取这些属性。

<!-- 父组件 -->
<Child class="box" data-test="hello" />
<!-- 子组件 -->
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
console.log(attrs.class) // 'box'
</script>
<template>
  <div v-bind="attrs">...</div>
</template>

三、全局状态管理

7. Pinia(或 Vuex)

将共享状态抽离到全局 Store 中,任意组件都可以直接读写。

// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() { count.value++ }
  return { count, increment }
})
<!-- 任意组件 -->
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
<template>
  <span>{{ counter.count }}</span>
  <button @click="counter.increment()">+</button>
</template>

8. 组合式函数(Composables)共享状态

将响应式状态和逻辑抽取到一个组合函数中,利用 Vue 的模块单例特性实现共享。

// composables/useSharedCount.js
import { ref } from 'vue'
const count = ref(0) // 模块作用域单例
export function useSharedCount() {
  function increment() { count.value++ }
  return { count, increment }
}
<!-- 任意组件 -->
<script setup>
import { useSharedCount } from '@/composables/useSharedCount'
const { count, increment } = useSharedCount()
</script>

四、其他常见传参方式

9. 事件总线(mitt / tiny-emitter)

Vue3 移除了 $on/$off,可引入第三方库如 mitt 实现任意组件间的发布-订阅通信。

10. 路由传参 (Vue Router)

通过路由参数、查询参数或状态传递数据。

11. 插槽(作用域插槽)

父组件通过作用域插槽接收子组件暴露的数据,实现数据回传渲染。

<!-- 子组件 -->
<template>
  <slot :data="list" :loading="isLoading" />
</template>
<!-- 父组件 -->
<Child>
  <template v-slot="{ data, loading }">
    <Spinner v-if="loading" />
    <List :items="data" />
  </template>
</Child>

五、传参方式对比总结

传参方式方向/范围响应式耦合度适用场景
props / emits父↔子标准父子通信,单向/事件通知
v-model父↔子(双向)表单输入、组件状态即时同步
ref + defineExpose父→子父组件命令式控制子组件行为
provide / inject祖先→后代✅ (引用)跨层级共享主题、配置等
$attrs父→子(透传)封装基础组件,透传 HTML 属性
Pinia / Vuex任意组件极低全局状态管理,多组件共享复杂状态
Composables任意组件极低轻量级跨组件共享状态或逻辑
事件总线任意组件极低极少数松耦合通信(不推荐)
路由传参跨页面页面跳转携带 id、查询参数等
作用域插槽子→父(数据)自定义子组件内容的渲染逻辑

六、如何选择?

没有银弹。实际开发中可以遵循以下准则:

  1. 首选最局部的方式:父子通信优先用 props + emits;需要双向绑定就用 v-model,避免过早使用全局状态。
  2. 跨层级但不频繁变动的数据,用 provide/inject,再配合 readonly 或回调限定修改权限。
  3. 多组件共享同一业务状态,毫不犹豫使用 Pinia,它的结构化管理和调试能力会省去大量排查时间。
  4. 封装基础组件时,通过 useAttrs()v-bind="$attrs" 透传属性,保持灵活性。
  5. 避免事件总线,除非你十分清楚自己在做什么,且能将全局事件控制在一个极小范围内。

理解每种方式的边界和开销,能让你在编写组件时更加游刃有余。Vue3 提供的组合式 API 配合其丰富的通信机制,几乎能够优雅地解决所有组件通信难题。

以上就是Vue3中常见的组件传参方式大全及对比详解的详细内容,更多关于Vue3组件传参方式大全的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文