Vue如何優(yōu)雅地復(fù)制一行帶附件的表格數(shù)據(jù)
前言
在做 Vue 項(xiàng)目的時(shí)候,大家是不是經(jīng)常遇到這樣的需求:
“點(diǎn)一下復(fù)制按鈕,把這行表格數(shù)據(jù)復(fù)制一份放在下方,除了附件字段之外其他都保留。”
聽起來簡(jiǎn)單?但一不小心就會(huì)踩到“對(duì)象引用”的大坑 —— 你以為復(fù)制的是一份新數(shù)據(jù),結(jié)果卻把原來的數(shù)據(jù)也一塊改了,尤其是像 poFile 這樣的附件字段,本來是保留原數(shù)據(jù),現(xiàn)在全被你“順手”置空了。
這篇文章就來聊聊:如何優(yōu)雅地復(fù)制一行帶附件的數(shù)據(jù),不破壞原始數(shù)據(jù)結(jié)構(gòu)?
需求背景與常見問題
我們有一個(gè)表格,每一行代表一個(gè)訂單物料。每一行可能有個(gè)附件字段 poFile,類型是數(shù)組,像這樣:
{
id: 'row-1',
name: '電容',
amount: 10,
poFile: [{ name: '報(bào)價(jià)單.pdf', url: '...' }]
}
現(xiàn)在我們要做一個(gè)“復(fù)制”功能:
- 把這行數(shù)據(jù)原樣復(fù)制;
- 附件字段
poFile需要置空; - 原始數(shù)據(jù)不受影響。
于是很多同學(xué)很自然地寫了這樣一段邏輯:
const tableobj = dataList.value[index] tableobj.poFile = [] // 清空附件 dataList.value.splice(index + 1, 0, cloneDeep(tableobj))
表面上看沒問題,但運(yùn)行完你會(huì)發(fā)現(xiàn):原始那一行的 poFile 也被清空了!
為什么?因?yàn)槟阒苯有薷牧嗽紝?duì)象的引用。
背后的 JS 原理小科普:對(duì)象是“引用類型”
在 JavaScript 里,對(duì)象是引用類型。當(dāng)你執(zhí)行:
const tableobj = dataList.value[index]
其實(shí) tableobj 和 dataList.value[index] 指向的是同一個(gè)對(duì)象地址。
所以當(dāng)你:
tableobj.poFile = []
其實(shí)也就等于把 dataList.value[index].poFile 清空了。
正確做法:用 cloneDeep 深拷貝新對(duì)象
解決這個(gè)問題的方法很簡(jiǎn)單:
修改前先 cloneDeep 一份副本,所有的“清空字段”都操作副本,原始對(duì)象不動(dòng)。
我們來重寫一下邏輯,分為兩種場(chǎng)景處理:普通復(fù)制 和 合并單元格模式復(fù)制。
Demo 代碼模塊
import cloneDeep from 'lodash/cloneDeep'
const copyData = (record, index) => {
let tableobj
if (props.isMergeCells) {
const curIndex = dataList.value.findIndex(items => {
return items.some(item => item.groupId === record.groupId)
})
const groupId = generateUUID()
// cloneDeep 是關(guān)鍵
tableobj = cloneDeep(dataList.value[curIndex]).map(item => {
item.id = generateUUID()
item.groupId = groupId
item.overLimitApproval = ''
item.poFile = [] // 附件置空
return item
})
dataList.value.splice(curIndex + 2, 0, ...tableobj, initTotalRow(groupId))
} else {
const originalRow = dataList.value[index]
if (originalRow) {
const copyRow = cloneDeep(originalRow)
if (copyRow?.id) {
delete copyRow.id
copyRow.groupId = generateUUID()
copyRow.overLimitApproval = ''
copyRow.poFile = [] // 清空附件
dataList.value.splice(index, 0, copyRow)
}
}
}
emit('edit', { key: 'amount' })
}
拆解講講:為啥這段代碼能解決問題
cloneDeep 是靈魂
lodash/cloneDeep 是做深拷貝的神器,它可以遞歸復(fù)制對(duì)象中的每一層結(jié)構(gòu),確保你拿到的是一個(gè)“全新”的副本。
const copyRow = cloneDeep(originalRow)
這一行就保證了:你對(duì) copyRow 的任何改動(dòng),都不會(huì)影響原始 originalRow。
清空 poFile 的方式建議用[]而不是''
附件字段通常是數(shù)組,代表可能有多個(gè)上傳文件。如果你把它清空成 '':
copyRow.poFile = ''
雖然能通過某些后端校驗(yàn),但可能會(huì)導(dǎo)致前端的 v-model 或 el-upload 報(bào)錯(cuò)。
建議統(tǒng)一使用:
copyRow.poFile = []
更符合結(jié)構(gòu)預(yù)期,也方便后續(xù)前端判斷文件上傳是否為空。
更進(jìn)一步:提取清理邏輯為復(fù)用函數(shù)
如果將來要清空的字段不止 poFile 和 overLimitApproval,可以提取成一個(gè)統(tǒng)一的清理函數(shù):
function resetCopyFields(row) {
row.poFile = []
row.overLimitApproval = ''
// 其他字段...
return row
}
調(diào)用時(shí)只需要:
resetCopyFields(copyRow)
讓邏輯更清晰,也更方便維護(hù)。
實(shí)際場(chǎng)景舉例:審批單據(jù)、銷售訂單、費(fèi)用報(bào)銷
這種“復(fù)制數(shù)據(jù)行但清空部分字段”的需求在很多系統(tǒng)里都有,比如:
- 審批系統(tǒng):復(fù)制上次填寫的數(shù)據(jù),但需要清空附件和備注;
- 銷售訂單:客戶下單的某個(gè)產(chǎn)品需要復(fù)制行修改數(shù)量,附件不帶;
- 報(bào)銷系統(tǒng):上個(gè)月差旅報(bào)銷復(fù)制,但要重新上傳票據(jù)。
這些場(chǎng)景下,如果不小心用了原始對(duì)象引用去處理,一不小心就把原始數(shù)據(jù)也改壞了,影響用戶體驗(yàn)。
總結(jié)
本文通過一個(gè)簡(jiǎn)單的復(fù)制邏輯,講清了一個(gè)非常常見但又容易忽略的問題 —— 引用對(duì)象修改導(dǎo)致原數(shù)據(jù)被篡改。
最后送上一句話:
只要是對(duì)象類型數(shù)據(jù),就別相信“復(fù)制了就是新的”這件事,除非你用 cloneDeep!
到此這篇關(guān)于Vue如何優(yōu)雅地復(fù)制一行帶附件的表格數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Vue復(fù)制表格數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elementUI Pagination 分頁指定最大頁的問題及解決方法(page-count)
項(xiàng)目中遇到數(shù)據(jù)量大,查詢的字段多,但用戶主要使用的是最近的一些數(shù)據(jù),1萬條以后的數(shù)據(jù)一般不使用,這篇文章主要介紹了elementUI Pagination 分頁指定最大頁的問題及解決方法(page-count),需要的朋友可以參考下2024-08-08
詳解Vue的computed(計(jì)算屬性)使用實(shí)例之TodoList
本篇文章主要介紹了詳解Vue的computed(計(jì)算屬性)使用實(shí)例之TodoList,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
vue如何自定義InputNumber計(jì)數(shù)器組件
這篇文章主要介紹了vue如何自定義InputNumber計(jì)數(shù)器組件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
vue3 表單搜索內(nèi)容回顯到地址欄的實(shí)例代碼
這篇文章主要介紹了vue3 表單搜索內(nèi)容回顯到地址欄的實(shí)例代碼,地址欄輸入內(nèi)容回顯到form表單,同理表單輸入內(nèi)容也要回顯到地址欄中,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
vue實(shí)現(xiàn)一個(gè)6個(gè)輸入框的驗(yàn)證碼輸入組件功能的實(shí)例代碼
這篇文章主要介紹了vue實(shí)現(xiàn)一個(gè)6個(gè)輸入框的驗(yàn)證碼輸入組件功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
VUE接入騰訊驗(yàn)證碼功能(滑塊驗(yàn)證)備忘
這篇文章主要介紹了VUE接入騰訊驗(yàn)證碼功能(滑塊驗(yàn)證)備忘,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
Vue自定義全局Toast和Loading的實(shí)例詳解
這篇文章主要介紹了Vue自定義全局Toast和Loading,需要的朋友可以參考下2019-04-04
詳解如何使用vue-cli腳手架搭建Vue.js項(xiàng)目
這篇文章主要介紹了詳解如何使用vue-cli腳手架搭建Vue.js項(xiàng)目 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05

