在Vue項(xiàng)目里管理彈窗組件是用ref還是用props詳解
在 Vue 項(xiàng)目里管理彈窗組件:用 ref 還是用 props?
在做業(yè)務(wù)后臺(tái)時(shí),頁(yè)面上常常會(huì)有很多彈窗:新增、編輯、詳情、排班表……這些彈窗如果直接寫(xiě)在頁(yè)面里,很快就會(huì)把父組件擠爆,于是我們會(huì)想到“抽成子組件”。但這時(shí)往往會(huì)遇到一個(gè)問(wèn)題:父組件到底該用 ref 調(diào)子組件方法,還是用 props + 事件 來(lái)控制子組件?這篇文章就圍繞這個(gè)問(wèn)題,把我們剛才討論過(guò)的內(nèi)容系統(tǒng)梳理一下。
兩種常見(jiàn)的控制方式
1. 用 props + 事件 控制子組件(推薦)
思路:
- 父組件通過(guò) props 把“狀態(tài)”傳給子組件(例如:是否可見(jiàn)、當(dāng)前模式、需要編輯的行數(shù)據(jù)等)。
- 子組件通過(guò) 事件 告訴父組件“我保存好了”“我關(guān)閉了”,父組件再?zèng)Q定要不要刷新列表等。
父組件負(fù)責(zé)的狀態(tài)(示例):
- 列表 & 查詢相關(guān)
- 當(dāng)前頁(yè)、每頁(yè)條數(shù)、篩選條件等。
- 和彈窗有關(guān)的最小狀態(tài)
- 某個(gè)編輯彈窗當(dāng)前是否顯示(例如:編輯彈窗的 visible 布爾值)。
- 編輯模式(新增 / 編輯)。
- 當(dāng)前被編輯的這一行數(shù)據(jù)(或它的 id)。
子組件負(fù)責(zé)的狀態(tài):
- 表單字段對(duì)象。
- 校驗(yàn)規(guī)則。
- 彈窗里的 loading 狀態(tài)。
- 內(nèi)部下拉列表、內(nèi)部接口請(qǐng)求等。
優(yōu)點(diǎn):
- 單向數(shù)據(jù)流清晰:父組件的數(shù)據(jù)流向子組件,子組件通過(guò)事件“回報(bào)”結(jié)果。
- 職責(zé)邊界清楚:父管“業(yè)務(wù)流程”,子管“彈窗內(nèi)部細(xì)節(jié)”。
- 高度可復(fù)用:這個(gè)彈窗子組件以后可以在很多父組件里復(fù)用,只要把必要的數(shù)據(jù)通過(guò) props 給它。
- 遷移到 Vue 3 更順暢:這種模式正是 Vue 3 推薦的,遷移時(shí)只需要把語(yǔ)法細(xì)節(jié)稍微調(diào)整一下(比如變成 v-model:visible、用 defineEmits 等)。
可以把這種模式理解為:> 父組件不“命令”子組件做事,而是“給它數(shù)據(jù) + 監(jiān)聽(tīng)它發(fā)出的事件”。
2. 用 $refs.xxx.xxx() 直接調(diào)用子組件方法
思路:
- 父組件給子組件一個(gè) ref 名,比如 groupEdit。
- 父組件在需要時(shí),通過(guò) this.$refs.groupEdit.open('edit', row) 之類的方式,直接調(diào)用子組件的方法,來(lái)打開(kāi)彈窗、注入數(shù)據(jù)。
父組件負(fù)責(zé)的內(nèi)容:
- 仍然要記住子組件對(duì)外暴露的 API,例如:open(mode, row)。
- 需要維護(hù)正確的 ref 名稱,并保證子組件提供了對(duì)應(yīng)方法。
子組件負(fù)責(zé)的內(nèi)容:
- 定義若干供父組件調(diào)用的方法,比如 open、close、reset 等。
- 在這些方法里再去設(shè)置自身的 visible、表單數(shù)據(jù)等內(nèi)部狀態(tài)。
優(yōu)點(diǎn):
- 用起來(lái)直觀:一眼就知道“調(diào)用這個(gè)函數(shù)就會(huì)打開(kāi)彈窗”,讀起來(lái)像是“調(diào)用組件的 API”,容易理解。
- 當(dāng)這個(gè)彈窗 只在一個(gè)地方用 時(shí),這種方式在短期內(nèi)也能“夠用”。
缺點(diǎn):
- 耦合度高:
- 父組件必須知道子組件的 ref 名字。
- 父組件必須知道子組件有哪些公共方法,以及這些方法的參數(shù)簽名。
- 不便于復(fù)用:
- 在別的頁(yè)面復(fù)用這個(gè)彈窗時(shí),也不得不按同樣的辦法注冊(cè) ref,調(diào)用同名方法。
- 不夠 Vue 化:
- Vue 更鼓勵(lì)“數(shù)據(jù) + 事件”的聲明式方式,而不是處處用 ref 去命令式調(diào)用。
Vue 3 遷移視角下的比較
如果你將來(lái)準(zhǔn)備把項(xiàng)目慢慢升級(jí)到 Vue 3,或者用 Composition API /
props + 事件 在 Vue 3 的表現(xiàn)
- Vue 3 官方依然推薦:
- 父?jìng)髯樱和ㄟ^(guò) props / v-model。
- 子傳父:通過(guò) emit 事件。
- 遷移時(shí),只需要:
- 把 .sync 寫(xiě)法變成 v-model:xxx。
- 在子組件里用 defineProps、defineEmits 等新語(yǔ)法替代老的 props / this.$emit 寫(xiě)法。
核心思想不變,只是“換一層語(yǔ)法皮”。這意味著:今天用 props + 事件 管子組件,將來(lái)改 Vue 3 時(shí),不用推翻設(shè)計(jì),只是重寫(xiě)語(yǔ)法。
$refs 調(diào)子組件方法在 Vue 3 的表現(xiàn)
- 傳統(tǒng) Options API 下 $refs 依然可以用。
- 但如果你改用
- 這樣一來(lái):
- 子組件要加“暴露 API”的聲明;
- 父組件仍要通過(guò) ref 調(diào)用這些方法;
- 一旦你多次重構(gòu)組件結(jié)構(gòu),容易出“小坑”。
也就是說(shuō):這種以 $refs 為中心的方式,在 Vue 3 里不能說(shuō)用不了,但和新的組合式風(fēng)格有點(diǎn)“別扭”,遷移時(shí)需要額外適配。
當(dāng)頁(yè)面上有“很多彈窗”時(shí)該怎么設(shè)計(jì)
現(xiàn)實(shí)業(yè)務(wù)中,一個(gè)頁(yè)面上可能有:
- 新增班組彈窗
- 編輯班組彈窗
- 排班表彈窗
- 詳情彈窗
- 審核意見(jiàn)彈窗
- …
如果所有彈窗的表單、校驗(yàn)、loading、內(nèi)部狀態(tài),統(tǒng)統(tǒng)塞到父組件的 data 里,父組件會(huì)非常臃腫,而且很多狀態(tài)和“列表主流程”并沒(méi)有直接關(guān)系。一個(gè)比較健康的拆分策略是:
父組件只維護(hù)“與業(yè)務(wù)流程相關(guān)的最小狀態(tài)”
例如:
- 當(dāng)前激活的是哪個(gè)彈窗:
- 某個(gè) bool:例如編輯彈窗的 visible。
- 彈窗模式:新增 / 編輯。
- 當(dāng)前作用的業(yè)務(wù)對(duì)象:
- 比如當(dāng)前選中的一行數(shù)據(jù),或當(dāng)前的業(yè)務(wù) id。
所有這些數(shù)據(jù)都直接體現(xiàn)“頁(yè)面業(yè)務(wù)流程”:比如“我要新增一個(gè)班組”,“我要編輯這行班組”,“我要查看這個(gè)班組的排班表”。
子組件維護(hù)“彈窗內(nèi)部的一切細(xì)節(jié)”
例如:
- 表單字段。
- 校驗(yàn)規(guī)則。
- 內(nèi)部 loading。
- 內(nèi)部下拉選項(xiàng)、接口請(qǐng)求邏輯。
- 內(nèi)部的 UI 結(jié)構(gòu)。
這樣,即使頁(yè)面上有很多彈窗:
- 父組件只是多了一些簡(jiǎn)單的“狀態(tài)標(biāo)志 + 當(dāng)前對(duì)象”。
- 復(fù)雜的邏輯都被封裝在一個(gè)個(gè)相對(duì)獨(dú)立的子組件里。
無(wú)論你最終選擇 props + 事件 還是 $refs,這個(gè)拆分邊界是更重要的設(shè)計(jì)點(diǎn)。
什么時(shí)候更適合用 props + 事件
可以優(yōu)先選用這一套的場(chǎng)景:
- 你希望:
- 組件可復(fù)用。
- 以后升級(jí) Vue 3、改 Composition API 時(shí)成本低。
- 團(tuán)隊(duì)代碼風(fēng)格更偏聲明式、數(shù)據(jù)驅(qū)動(dòng)。
- 一個(gè)彈窗可能會(huì)在多個(gè)頁(yè)面被復(fù)用,例如:
- 公共的“選擇用戶”彈窗。
- 多處使用的“編輯班組”彈窗等。
- 你想要更清晰的邊界:父組件描述“業(yè)務(wù)流程”,子組件只管“具體表現(xiàn)和交互”。
總結(jié)成一句話:> 只要不是非常臨時(shí)的一次性組件,props + 事件 一般都是更穩(wěn)妥的首選方案。
什么時(shí)候 $refs 也可以接受
盡管不推薦作為默認(rèn)選擇,但在一些情況下,$refs 也是可以使用的:
- 這個(gè)彈窗 只會(huì)在當(dāng)前頁(yè)面里使用,沒(méi)有復(fù)用需求。
- 你很希望有一個(gè)“像函數(shù)一樣”的入口,比如:
- 在某個(gè)復(fù)雜流程中,需要多次、不同參數(shù)地調(diào)用子組件的能力。
- 調(diào)用鏈比較長(zhǎng)時(shí),用 $refs.xxx.open(param) 比一層層傳 props 來(lái)得更好讀。
- 團(tuán)隊(duì)內(nèi)部對(duì) $refs 的用法有統(tǒng)一約定:
- 比如統(tǒng)一所有側(cè)滑彈窗子組件都對(duì)外提供 open(row) 方法。
- 這樣即使用 $refs,也還算規(guī)范。
哪怕如此,也建議:
- 不要在一個(gè)組件里到處用 $refs 驅(qū)動(dòng)邏輯。
- 盡量將 $refs 使用場(chǎng)景局限在“少數(shù)真正需要命令式行為”的地方。
總結(jié):實(shí)際項(xiàng)目里的推薦組合
綜合上面所有點(diǎn),可以給出一個(gè)比較落地的建議組合:
- 通用彈窗 / 表單組件:
- 用 props + 事件 管理;
- 父組件保持最小狀態(tài),子組件封裝內(nèi)部邏輯;
- 為未來(lái)遷移 Vue 3 做好準(zhǔn)備。
- 特殊場(chǎng)景、強(qiáng)命令式的東西(少數(shù)):
- 可以用 $refs + 子組件暴露少量方法;
- 但要克制使用,并在團(tuán)隊(duì)內(nèi)達(dá)成共識(shí)。
如果你現(xiàn)在正在重構(gòu)一個(gè)老頁(yè)面、抽離一堆彈窗組件,一個(gè)實(shí)用的操作順序是:
- 先盡量用 props + 事件 把復(fù)雜表單彈窗都抽出去。
- 只有在確實(shí)“很不方便”時(shí),再為某個(gè)子組件補(bǔ)一個(gè) open() 形式的 API,配合 $refs 使用。
這樣既能兼顧當(dāng)前開(kāi)發(fā)效率,也不會(huì)把未來(lái)的維護(hù)成本提前埋雷。
總結(jié)
到此這篇關(guān)于在Vue項(xiàng)目里管理彈窗組件是用ref還是用props的文章就介紹到這了,更多相關(guān)Vue用ref還是props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Vue3.0中ElementPlus<input輸入框自動(dòng)獲取焦點(diǎn)>
這篇文章主要給大家介紹了關(guān)于Vue3.0中ElementPlus<input輸入框自動(dòng)獲取焦點(diǎn)>的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用vue3.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-04-04
Vue項(xiàng)目如何在js文件里獲取路由參數(shù)及路由跳轉(zhuǎn)
日常業(yè)務(wù)中路由跳轉(zhuǎn)的同時(shí)傳遞參數(shù)是比較常見(jiàn)的,下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目如何在js文件里獲取路由參數(shù)及路由跳轉(zhuǎn)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated
安裝vue腳手架報(bào)錯(cuò)可能具體原因比較多,可以根據(jù)報(bào)錯(cuò)信息進(jìn)行排查,本文主要介紹了npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated,感興趣的可以了解一下2023-11-11
vue中v-cloak解決刷新或者加載出現(xiàn)閃爍問(wèn)題(顯示變量)
這篇文章主要介紹了vue中v-cloak解決刷新或者加載出現(xiàn)閃爍問(wèn)題(顯示變量) ,需要的朋友可以參考下2018-04-04
vue動(dòng)態(tài)綁定多個(gè)類名方法詳解(:class動(dòng)態(tài)綁定多個(gè)類名)
vue中可以通過(guò):class=""這樣來(lái)根據(jù)一定的條件來(lái)動(dòng)態(tài)添加class,但是有時(shí)候需要判斷的條件比較多,需要?jiǎng)討B(tài)添加的class也比較多,下面這篇文章主要給大家介紹了關(guān)于vue動(dòng)態(tài)綁定多個(gè)類名(:class動(dòng)態(tài)綁定多個(gè)類名)的相關(guān)資料,需要的朋友可以參考下2022-11-11

