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

