Vue3 動(dòng)態(tài)ref問(wèn)題及解決
1.問(wèn)題描述
在Vue 3項(xiàng)目中,當(dāng)使用動(dòng)態(tài)ref來(lái)引用組件時(shí),刪除組件后發(fā)現(xiàn)ref對(duì)象中對(duì)應(yīng)的key仍然存在,只是值變?yōu)閌null`,而不是完全刪除該key。
在一個(gè)可拖拽的卡片列表組件中:
- 使用動(dòng)態(tài)ref來(lái)引用每個(gè)卡片中的數(shù)據(jù)列表組件
- 當(dāng)刪除卡片時(shí),需要同時(shí)清理對(duì)應(yīng)的ref引用
- 發(fā)現(xiàn)刪除后ref對(duì)象中key仍存在,值為`null`
2.示例代碼
<template>
<div>
<a-card v-for="item in dragList" :key="item.id">
<!-- 動(dòng)態(tài)ref的使用 -->
<data-list
:ref="el => { dataListRef[item.id] = el }"
:doc-id="item.id"
:open-type="item.openType"
/>
</a-card>
</div>
</template><script setup lang="ts">
import { ref } from 'vue';
const dragList = ref<any[]>([]);
const dataListRef = ref<Record<string, any>>({});
// 刪除卡片方法
function remove(index: number) {
const current = dragList.value[index];
// 處理編輯狀態(tài)
if (current.openType === OPEN_WRITE) {
const docIds = [current.id];
closeDocEntry(docIds);
}
// 從列表中移除
dragList.value.splice(index, 1);
// 更新其他項(xiàng)目的源列表
for (let ele of dragList.value) {
const oldSourceList = ele.sourceList;
ele.sourceList = oldSourceList.filter((item: any) => item.sourceId !== current.id);
}
// Vue 會(huì)自動(dòng)處理動(dòng)態(tài) ref 的清理,無(wú)需手動(dòng)刪除,即使執(zhí)行了刪除方法,也不會(huì)刪除key
// dataListRef.value[current.id] 會(huì)自動(dòng)變?yōu)?null
}
// 刷新所有數(shù)據(jù)列表
function reflushAllDragList() {
Object.keys(dataListRef.value).forEach((key: string) => {
// 過(guò)濾掉已經(jīng)被刪除的組件(值為null的情況)
if (dataListRef.value[key]) {
dataListRef.value[key].refresh();
}
});
}
</script>說(shuō)明:
①可以使用數(shù)組或者對(duì)象存儲(chǔ)組件的ref對(duì)象實(shí)例,因?yàn)榻M件是循環(huán)生成的,所以每個(gè)組件的ref對(duì)象需要通過(guò)這種方式進(jìn)行存儲(chǔ)。
② 循環(huán)生成的多個(gè)組件可以通過(guò)點(diǎn)擊刪除按鈕進(jìn)行刪除,當(dāng)組件刪除時(shí)原本想刪除ref對(duì)象中的組件對(duì)應(yīng)的ref對(duì)象,但發(fā)現(xiàn)無(wú)法刪除,最后的結(jié)果是key存在,value為null
3.原因分析
Vue 3中的動(dòng)態(tài)ref機(jī)制有以下特點(diǎn):
- 組件掛載時(shí):動(dòng)態(tài)ref會(huì)自動(dòng)將組件實(shí)例賦值給指定的key
- 組件卸載時(shí):Vue會(huì)自動(dòng)將對(duì)應(yīng)的ref值設(shè)置為`null`,但**不會(huì)刪除key**
- 響應(yīng)式處理:Vue的響應(yīng)式系統(tǒng)會(huì)在組件生命周期中自動(dòng)管理ref的狀態(tài)
為什么key不會(huì)被刪除
這是Vue 3的設(shè)計(jì)行為,不是bug:
- Vue需要保持ref對(duì)象的響應(yīng)式結(jié)構(gòu)完整性
- 避免在組件頻繁掛載/卸載時(shí)產(chǎn)生不必要的響應(yīng)式觸發(fā)
- 提供了更好的性能優(yōu)化
4.解決方案
因?yàn)闊o(wú)法刪除,所以在后續(xù)使用ref對(duì)象時(shí),需要進(jìn)行判斷是否為null,如果不為null,則執(zhí)行相關(guān)方法。
function reflushAllDragList() {
Object.keys(dataListRef.value).forEach((key: string) => {
// 過(guò)濾掉已經(jīng)被刪除的組件(值為null的情況)
// 當(dāng)刪除card時(shí),Vue會(huì)自動(dòng)把dataListRef的對(duì)應(yīng)key的值設(shè)置為null
// 不用進(jìn)行手動(dòng)刪除,即使手動(dòng)刪除,key也存在
if (dataListRef.value[key]) {
dataListRef.value[key].refresh();
}
});
}5.總結(jié)
Vue 3的動(dòng)態(tài)ref在組件卸載時(shí)會(huì)自動(dòng)將值設(shè)置為`null`但保留key,這是正常的設(shè)計(jì)行為。
正確的處理方式是:
- 不要嘗試手動(dòng)刪除ref中的key
- 在使用ref時(shí)進(jìn)行null檢查
- 信任Vue的自動(dòng)管理機(jī)制
這樣可以確保代碼的穩(wěn)定性和可維護(hù)性。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue導(dǎo)出excel的兩個(gè)常用方式介紹與對(duì)比
這篇文章主要為大家詳細(xì)介紹了Vue導(dǎo)出excel的兩個(gè)常用方式,分別為前端vue+XLSX導(dǎo)出excel和vue+后端POI?導(dǎo)出excel,感興趣的小伙伴可以了解下2025-01-01
vue實(shí)現(xiàn)動(dòng)態(tài)綁定行內(nèi)樣式style的backgroundImage
這篇文章主要介紹了vue實(shí)現(xiàn)動(dòng)態(tài)綁定行內(nèi)樣式style的backgroundImage方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
antd?Vue實(shí)現(xiàn)Login登錄頁(yè)面布局案例詳解?附帶驗(yàn)證碼驗(yàn)證功能
這篇文章主要介紹了antd?Vue實(shí)現(xiàn)Login登錄頁(yè)面布局案例詳解附帶驗(yàn)證碼驗(yàn)證功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
vue中動(dòng)態(tài)參數(shù)與計(jì)算屬性的使用方法
在平時(shí)vue開(kāi)發(fā)中,我們經(jīng)常會(huì)用到計(jì)算屬性(計(jì)算屬性只有在它的相關(guān)依賴發(fā)生改變時(shí)才會(huì)重新求值)來(lái)計(jì)算我們需要的數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于vue中動(dòng)態(tài)參數(shù)與計(jì)算屬性使用的相關(guān)資料,需要的朋友可以參考下2021-08-08
vue-cli 3.0 引入mint-ui報(bào)錯(cuò)問(wèn)題及解決
這篇文章主要介紹了vue-cli 3.0 引入mint-ui報(bào)錯(cuò)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Vue+OpenLayers進(jìn)行項(xiàng)目開(kāi)發(fā)的完整指南
在前端開(kāi)發(fā)中,OpenLayers?是一個(gè)強(qiáng)大的開(kāi)源地圖庫(kù),可以用于?WebGIS?開(kāi)發(fā),下面小編就來(lái)和大家詳細(xì)講講Vue使用OpenLayers進(jìn)行項(xiàng)目開(kāi)發(fā)的具體步驟2025-06-06
前端vue按1920*1080設(shè)計(jì)圖的頁(yè)面適配屏幕縮放并適配4K屏詳解
最近在做一個(gè)數(shù)據(jù)可視化的項(xiàng)目,整個(gè)項(xiàng)目全是大屏展示,期間也是遇到很多問(wèn)題,最令人頭疼的就是大屏的適配,下面這篇文章主要給大家介紹了前端vue按1920*1080設(shè)計(jì)圖的頁(yè)面適配屏幕縮放并適配4K屏的相關(guān)資料,需要的朋友可以參考下2022-11-11
vue-cli4創(chuàng)建項(xiàng)目導(dǎo)入Element-UI踩過(guò)的坑及解決
這篇文章主要介紹了vue-cli4創(chuàng)建項(xiàng)目導(dǎo)入Element-UI踩過(guò)的坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04

