Vue3 組件通信與插槽

Vue3 組件通信方式全解(10種方案)


一、組件通信方式概覽

通信方式適用場景數據流向復雜度
Props/自定義事件父子組件簡單通信父 ? 子?
v-model 雙向綁定父子表單組件父 ? 子??
Provide/Inject跨層級組件通信祖先 → 后代??
事件總線任意組件間通信任意方向???
模板引用(ref)父操作子組件父 → 子?
Pinia 狀態管理復雜應用狀態共享全局共享???
瀏覽器存儲持久化數據共享全局共享???
attrs/attrs/listeners透傳屬性/事件父 → 深層子組件??
作用域插槽子向父傳遞渲染內容子 → 父??
路由參數頁面間數據傳遞頁面間?

二、核心通信方案詳解

1. Props / 自定義事件(父子通信)

<!-- 父組件 Parent.vue -->
<template><Child :message="parentMsg" @update="handleUpdate"/>
</template><script setup>
import { ref } from 'vue'
const parentMsg = ref('Hello from parent')const handleUpdate = (newMsg) => {parentMsg.value = newMsg
}
</script><!-- 子組件 Child.vue -->
<script setup>
defineProps(['message'])
const emit = defineEmits(['update'])const sendToParent = () => {emit('update', 'New message from child')
}
</script>

2. v-model 雙向綁定(表單場景)

<!-- 父組件 -->
<CustomInput v-model="username" /><!-- 子組件 CustomInput.vue -->
<template><input :value="modelValue"@input="$emit('update:modelValue', $event.target.value)">
</template><script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

3. Provide/Inject(跨層級)

// 祖先組件
import { provide, ref } from 'vue'
const theme = ref('dark')provide('theme', {theme,toggleTheme: () => {theme.value = theme.value === 'dark' ? 'light' : 'dark'}
})// 后代組件
import { inject } from 'vue'
const { theme, toggleTheme } = inject('theme')

4. 事件總線 mitt(任意組件)

// eventBus.js
import mitt from 'mitt'
export const emitter = mitt()// 組件A(發送)
emitter.emit('global-event', { data: 123 })// 組件B(接收)
emitter.on('global-event', (data) => {console.log(data)
})

5. Pinia 狀態管理(復雜應用)

// stores/user.js
export const useUserStore = defineStore('user', {state: () => ({ name: 'Alice' }),actions: {updateName(newName) {this.name = newName}}
})// 組件使用
const userStore = useUserStore()
userStore.updateName('Bob')

6. 作用域插槽(子傳父)

<!-- 子組件 -->
<template><slot :data="childData" />
</template><script setup>
const childData = { message: 'From child' }
</script><!-- 父組件 -->
<Child><template #default="{ data }">{{ data.message }}</template>
</Child>

三、進階通信技巧

1. 多層屬性透傳

// 父組件
<GrandParent><Parent><Child /></Parent>
</GrandParent>// GrandParent.vue
<template><Parent v-bind="$attrs"><slot /></Parent>
</template>// 使用 inheritAttrs: false 關閉自動繼承

2. 動態組件通信

<component :is="currentComponent" @custom-event="handleEvent"
/>

3. 自定義 Hook 封裝

// hooks/useCounter.js
export function useCounter(initial = 0) {const count = ref(initial)const increment = () => count.value++return { count, increment }
}// 組件A
const { count: countA } = useCounter()// 組件B
const { count: countB } = useCounter(10)

4. 全局事件總線加強版

// eventBus.ts
type EventMap = {'user-login': { userId: string }'cart-update': CartItem[]
}export const emitter = mitt<EventMap>()// 安全使用
emitter.emit('user-login', { userId: '123' })

四、最佳實踐指南

  1. 簡單場景優先方案

    • 父子通信:Props + 自定義事件

    • 表單組件:v-model

    • 簡單共享數據:Provide/Inject

  2. 復雜應用推薦方案

    • 全局狀態管理:Pinia

    • 跨組件通信:事件總線

    • 持久化數據:localStorage + Pinia 插件

  3. 性能優化技巧

    • 避免在 Props 中傳遞大型對象

    • 使用 computed 屬性優化渲染

    • 對頻繁觸發的事件進行防抖處理

    • 及時清理事件監聽器

  4. TypeScript 增強

// Props 類型定義
defineProps<{title: stringdata: number[]
}>()// 事件類型定義
defineEmits<{(e: 'update', value: string): void(e: 'delete', id: number): void
}>()

五、常見問題解決方案

Q1: 如何避免 Props 層層傳遞?
? 使用 Provide/Inject 或 Pinia

Q2: 子組件如何修改父組件數據?
? 通過自定義事件通知父組件修改

Q3: 如何實現兄弟組件通信?
? 方案1:通過共同的父組件中轉
? 方案2:使用事件總線或 Pinia

Q4: 如何保證響應式數據安全?
? 使用 readonly 限制修改權限:

provide('config', readonly(config))

Q5: 如何實現跨路由組件通信?
? 使用 Pinia 狀態管理
? 通過路由參數傳遞
? 使用 localStorage 持久化存儲


? ?

插槽詳解


一、插槽核心概念

1. 插槽作用

允許父組件向子組件插入自定義內容,實現組件的高度可定制化

2. 組件通信對比
通信方式數據流向內容類型
Props父 → 子純數據
插槽父 → 子模板/組件/HTML片段

二、基礎插槽類型

1. 默認插槽

子組件

<!-- ChildComponent.vue -->
<template><div class="card"><slot>默認內容(父組件未提供時顯示)</slot></div>
</template>

父組件

<ChildComponent><p>自定義卡片內容</p>
</ChildComponent>
2. 具名插槽

子組件

<template><div class="layout"><header><slot name="header"></slot></header><main><slot></slot> <!-- 默認插槽 --></main><footer><slot name="footer"></slot></footer></div>
</template>

父組件

<ChildComponent><template #header><h1>頁面標題</h1></template><p>主內容區域</p><template v-slot:footer><p>版權信息 ? 2023</p></template>
</ChildComponent>

三、作用域插槽(核心進階)

1. 數據傳遞原理

子組件向插槽傳遞數據 → 父組件接收使用

子組件

<template><ul><li v-for="item in items" :key="item.id"><slot :item="item" :index="index"></slot></li></ul>
</template><script setup>
const items = ref([{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }])
</script>

父組件

<ChildComponent><template #default="{ item, index }"><span>{{ index + 1 }}. {{ item.name }}</span><button @click="deleteItem(item.id)">刪除</button></template>
</ChildComponent>
2. 應用場景示例

場景:表格組件支持自定義列渲染
子組件

<template><table><thead><tr><th v-for="col in columns" :key="col.key">{{ col.title }}</th></tr></thead><tbody><tr v-for="row in data" :key="row.id"><td v-for="col in columns" :key="col.key"><slot :name="col.key" :row="row">{{ row[col.key] }} <!-- 默認顯示 --></slot></td></tr></tbody></table>
</template>

父組件

<DataTable :data="users" :columns="columns"><template #action="{ row }"><button @click="editUser(row.id)">編輯</button><button @click="deleteUser(row.id)">刪除</button></template><template #status="{ row }"><span :class="row.status">{{ row.status | statusText }}</span></template>
</DataTable>

四、動態插槽名

子組件

<template><div class="dynamic-slot"><slot :name="slotName"></slot></div>
</template><script setup>
defineProps({slotName: {type: String,default: 'default'}
})
</script>

父組件

<ChildComponent :slotName="currentSlot"><template #[currentSlot]><p>動態插槽內容(當前使用 {{ currentSlot }} 插槽)</p></template>
</ChildComponent>

五、高級技巧

1. 插槽繼承($slots)

訪問子組件插槽內容:

// 子組件內部
const slots = useSlots()
console.log(slots.header()) // 獲取具名插槽內容
2. 渲染函數中使用插槽
// 使用 h() 函數創建元素
export default {render() {return h('div', [this.$slots.default?.() || '默認內容',h('div', { class: 'footer' }, this.$slots.footer?.())])}
}

六、最佳實踐指南

  1. 命名規范

    • 使用小寫字母 + 連字符命名具名插槽(如?#user-avatar

    • 避免使用保留字作為插槽名(如?defaultitem

  2. 性能優化

    <!-- 通過 v-if 控制插槽內容渲染 -->
    <template #header v-if="showHeader"><HeavyComponent />
    </template>
  3. 類型安全(TypeScript)

    // 定義作用域插槽類型
    defineSlots<{default?: (props: { item: T; index: number }) => anyheader?: () => anyfooter?: () => any
    }>()

七、常見問題解答

Q1:如何強制要求必須提供某個插槽

// 子組件中驗證
export default {mounted() {if (!this.$slots.header) {console.error('必須提供 header 插槽內容')}}
}

Q2:插槽內容如何訪問子組件方法?

<!-- 子組件暴露方法 -->
<slot :doSomething="handleAction"></slot><!-- 父組件使用 -->
<template #default="{ doSomething }"><button @click="doSomething">觸發子組件方法</button>
</template>

Q3:如何實現插槽內容過渡動畫?

<transition name="fade" mode="out-in"><slot></slot>
</transition>

八、綜合應用案例

可配置的模態框組件

<!-- Modal.vue -->
<template><div class="modal" v-show="visible"><div class="modal-header"><slot name="header"><h2>{{ title }}</h2><button @click="close">×</button></slot></div><div class="modal-body"><slot :close="close"></slot></div><div class="modal-footer"><slot name="footer"><button @click="close">關閉</button></slot></div></div>
</template>

父組件使用

<Modal v-model:visible="showModal" title="自定義標題"><template #header><h1 style="color: red;">緊急通知</h1></template><template #default="{ close }"><p>確認刪除此項?</p><button @click="confirmDelete; close()">確認</button></template><template #footer><button @click="showModal = false">取消</button></template>
</Modal>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78400.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【KWDB 創作者計劃】_嵌入式硬件篇---數字電子器件

文章目錄 前言一、系列前綴(如 "74" 或 "54")74(商用級)54(工業級)二、邏輯家族(如 "LS"、"HC"、"HCT" 等)TTL(晶體管-晶體管邏輯)家族CMOS(互補金屬氧化物半導體)家族BiCMOS(雙極 CMOS)家族三、功能編號(如…

黃勇的《架構探險:從Java到大數據》內容詳解

《架構探險&#xff1a;從Java到大數據》內容詳解 1. 書籍核心主題 黃勇的《架構探險&#xff1a;從Java到大數據》是一本系統性探討架構設計演進的著作&#xff0c;結合Java技術棧和大數據場景&#xff0c;深入分析了從單體架構到分布式、微服務、云原生的演進路徑&#xff0…

【動手學強化學習】番外8-IPPO應用框架學習與復現

文章目錄 一、待解決問題1.1 問題描述1.2 解決方法 二、方法詳述2.1 必要說明&#xff08;1&#xff09;MAPPO 與 IPPO 算法的區別在于什么地方&#xff1f;&#xff08;2&#xff09;IPPO 算法應用框架主要參考來源 2.2 應用步驟2.2.1 搭建基礎環境2.2.2 IPPO 算法實例復現&am…

驅動開發硬核特訓 · Day 17:深入掌握中斷機制與驅動開發中的應用實戰

&#x1f3a5; 視頻教程請關注 B 站&#xff1a;“嵌入式 Jerry” 一、前言 在嵌入式驅動開發中&#xff0c;“中斷”幾乎無處不在。無論是 GPIO 按鍵、串口通信、網絡設備&#xff0c;還是 SoC 上的各種控制器&#xff0c;中斷都扮演著核心觸發機制的角色。對中斷機制掌握程度…

通過門店銷售明細表用PySpark得到每月每個門店的銷冠和按月的同比環比數據

假設我在Amazon S3上有銷售表的Parquet數據文件的路徑&#xff0c;包含ID主鍵、門店ID、日期、銷售員姓名和銷售額&#xff0c;需要分別用PySpark的SparkSQL和Dataframe API統計出每個月所有門店和各門店銷售額最高的人&#xff0c;不一定是一個人&#xff0c;以及他所在的門店…

PostgreSQL 常用日志

PostgreSQL 常用日志詳解 PostgreSQL 提供了多種日志類型&#xff0c;用于監控數據庫活動、排查問題和優化性能。以下是 PostgreSQL 中最常用的日志類型及其配置和使用方法。 一、主要日志類型 日志類型文件位置主要內容用途服務器日志postgresql-<日期>.log服務器運行…

MySQL 存儲過程:解鎖數據庫編程的高效密碼

目錄 一、什么是存儲過程?二、創建存儲過程示例 1:創建一個簡單的存儲過程示例 2:創建帶輸入參數的存儲過程示例 3:創建帶輸出參數的存儲過程三、調用存儲過程調用無參數存儲過程調用帶輸入參數的存儲過程調用帶輸出參數的存儲過程四、存儲過程中的流控制語句示例 1:使用 …

基于STM32的物流搬運機器人

功能&#xff1a;智能循跡、定距夾取、顏色切換、自動跟隨、自動避障、聲音夾取、藍牙遙控、手柄遙控、顏色識別夾取、循跡避障、循跡定距…… 包含內容&#xff1a;完整源碼、使用手冊、原理圖、視頻演示、PPT、論文參考、其余資料 資料只私聊

pg_jieba 中文分詞

os: centos 7.9.2009 pg: 14.7 pg_jieba 依賴 cppjieba、limonp pg_jieba 下載 su - postgreswget https://github.com/jaiminpan/pg_jieba/archive/refs/tags/vmaster.tar.gzunzip ./pg_jieba-master cd ~/pg_jieba-mastercppjieba、limonp 下載 su - postgrescd ~/pg_jie…

基于Python+Flask的MCP SDK響應式文檔展示系統設計與實現

以下是使用Python Flask HTML實現的MCP文檔展示系統&#xff1a; # app.py from flask import Flask, render_templateapp Flask(__name__)app.route(/) def index():return render_template(index.html)app.route(/installation) def installation():return render_templa…

【“星睿O6”AI PC開發套件評測】GPU矩陣指令算力,GPU帶寬和NPU算力測試

【“星睿O6”AI PC開發套件評測】GPU矩陣指令算力&#xff0c;GPU帶寬和NPU算力測試 安謀科技、此芯科技與瑞莎計算機聯合打造了面向AI PC、邊緣、機器人等不同場景的“星睿O6”開發套件 該套件異構集成了Armv9 CPU核心、Arm Immortalis? GPU以及安謀科技“周易”NPU 開箱和…

【Go語言】RPC 使用指南(初學者版)

RPC&#xff08;Remote Procedure Call&#xff0c;遠程過程調用&#xff09;是一種計算機通信協議&#xff0c;允許程序調用另一臺計算機上的子程序&#xff0c;就像調用本地程序一樣。Go 語言內置了 RPC 支持&#xff0c;下面我會詳細介紹如何使用。 一、基本概念 在 Go 中&…

11、Refs:直接操控元素——React 19 DOM操作秘籍

一、元素操控的魔法本質 "Refs是巫師與麻瓜世界的連接通道&#xff0c;讓開發者能像操控魔杖般精準控制DOM元素&#xff01;"魔杖工坊的奧利凡德先生輕撫著魔杖&#xff0c;React/Vue的refs能量在杖尖躍動。 ——以神秘事務司的量子糾纏理論為基&#xff0c;揭示DOM…

MinIO 教程:從入門到Spring Boot集成

文章目錄 一. MinIO 簡介1. 什么是MinIO&#xff1f;2. 應用場景 二. 文件系統存儲發展史1. 服務器磁盤&#xff08;本地存儲&#xff09;2. 分布式文件系統(如 HDFS、Ceph、GlusterFS)3. 對象存儲&#xff08;如 MinIO、AWS S3&#xff09;4.對比總結5.選型建議6.示例方案 三.…

電競俱樂部護航點單小程序,和平地鐵俱樂部點單系統,三角洲護航小程序,暗區突圍俱樂部小程序

電競俱樂部護航點單小程序開發&#xff0c;和平地鐵俱樂部點單系統&#xff0c;三角洲護航小程序&#xff0c;暗區突圍俱樂部小程序開發 端口包含&#xff1a; 超管后臺&#xff0c; 老板端&#xff0c;打手端&#xff0c;商家端&#xff0c;客服端&#xff0c;管事端&#x…

基于 IPMI + Kickstart + Jenkins 的 OS 自動化安裝

Author&#xff1a;Arsen Date&#xff1a;2025/04/26 目錄 環境要求實現步驟自定義 ISO安裝 ipmitool安裝 NFS定義 ks.cfg安裝 HTTP編寫 Pipeline 功能驗證 環境要求 目標服務器支持 IPMI / Redfish 遠程管理&#xff08;如 DELL iDRAC、HPE iLO、華為 iBMC&#xff09;&…

如何在SpringBoot中通過@Value注入Map和List并使用YAML配置?

在SpringBoot開發中&#xff0c;我們經常需要從配置文件中讀取各種參數。對于簡單的字符串或數值&#xff0c;直接使用Value注解就可以了。但當我們需要注入更復雜的數據結構&#xff0c;比如Map或者List時&#xff0c;該怎么操作呢&#xff1f;特別是使用YAML這種更人性化的配…

短信驗證碼安全實戰:三網API+多語言適配開發指南

在短信服務中&#xff0c;創建自定義簽名是發送通知、驗證信息和其他類型消息的重要步驟。萬維易源提供的“三網短信驗證碼”API為開發者和企業提供了高效、便捷的自定義簽名創建服務&#xff0c;可以通過簡單的接口調用提交簽名給運營商審核。本文將詳細介紹如何使用該API&…

RabbitMQ和Seata沖突嗎?Seata與Spring中的事務管理沖突嗎

1. GlobalTransactional 和 Transactional 是否沖突&#xff1f; 答&#xff1a;不沖突&#xff0c;它們可以協同工作&#xff0c;但作用域不同。 Transactional: 這是 Spring 提供的注解&#xff0c;用于管理單個數據源內的本地事務。在你當前的 register 方法中&#xff0c…

一臺服務器已經有個python3.11版本了,如何手動安裝 Python 3.10,兩個版本共存

環境&#xff1a; debian12.8 python3.11 python3.10 問題描述&#xff1a; 一臺服務器已經有個python3.11版本了&#xff0c;如何手動安裝 Python 3.10&#xff0c;兩個版本共存 解決方案&#xff1a; 1.下載 Python 3.10 源碼&#xff1a; wget https://www.python.or…