前言 ✍
业务场景:
后端会返回表单数据,其中表单数据包含列表数据。前端需要对列表数据进行增删查改。
前端处理后,最后将最新数据返回给到后端。
假设后端返回的数据结构如下:
js
const formData = ref({
baseAct: {
name: '活动一',
shopName: '店铺-四叶草',
startTime: '2025-08-20 17:44:00'
},
productList: [
{ id: 1, productName: '商品一', stock: '12', price: '12.5', disPrice: '11' },
{ id: 2, productName: '商品二', stock: '12', price: '12.5', disPrice: '11' }
]
})
回显:编辑修改表单信息。编辑表单信息除了会编辑基础信息外,还会修改商品列表信息,如折扣价,参与活动商品数量等等。
这些问题不大,对其进行表单字段绑定即可。。。。
进入正文 ✍
由于实际情况下 productList 这部分商品数量很多,名称也很相似。
这就导致了用户在查找具体商品进行修改参数时比较麻烦。
因此,需要这里增加了一个需求:增加一个搜索框,用于搜索 productList
在这之前,我都是用俩个变量来处理这种情况的:一个用于存放全部 productList ,一个存放搜索结果 searchProductList
js
const search = (key) => {
if (!key.value) {
searchProductList.value = formData.value.productList.filter(item => item.productName.includes(key.value))
} else {
searchProductList.value = formData.value.productList
}
}
js
<el-table :data="searchProductList">
<el-table-column prop="productName" label="商品名称" />
<el-table-column prop="stock" label="库存数量">
<template #default="{ row }">
<el-input v-model="row.stock"></el-input>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" />
<el-table-column prop="disPrice" label="折扣价格" />
<el-table-column prop="operation" label="操作">
<template #default="{ row }">
<el-button @click="remove(row)">移除</el-button>
</template>
</el-table-column>
</el-table>
此时页面双向绑定 searchProductList 下的 stock
字段,当对其进行修改时,是能够正常响应到 formData
。
原因是 searchProductList
与 formData.value.productList
产生了地址引用。
目前到这里,没发现什么问题。
问题来了 ✍
实际业务中除了修改原有 productList
中的数据参数值外,还需要对其进行删除和添加。
那么此时,我们需要怎么修改,是直接往 searchProductList
还是 productList
添加数据。
给大家三秒钟思考一下。
目前这种情况下,前端需要去维护两个数组 searchProductList
和 productList
。
才能确保查询状态没有出现问题
关键来了:
这种情况:需要产生一种效果就是 searchProductList 是 productList 的一个子集 ,只要修改 productList
数据,searchProductList
将能得到体现。
进入主角 computed ✍
computed 则就能产生上面的效果。
js
<template>
<div>
<el-input v-model="key" style="margin: 12px; width: 200px;" placeholder="请输入关键字"></el-input>
<el-button @click="add">增加一条数据</el-button>
<el-table :data="searchProductList">
<el-table-column prop="productName" label="商品名称" />
<el-table-column prop="stock" label="库存数量">
<template #default="{ row }">
<el-input v-model="row.stock" @change="change"></el-input>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" />
<el-table-column prop="disPrice" label="折扣价格" />
<el-table-column prop="operation" label="操作">
<template #default="{ row }">
<el-button @click="remove(row)">移除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { computed, ref } from 'vue'
const key = ref('')
const searchProductList = computed(() => {
if (!key.value) return formData.value.productList
return formData.value.productList.filter(item => item.productName.includes(key.value))
})
const formData = ref({
baseAct: {
name: '活动一',
shopName: '店铺-四叶草',
startTime: '2025-08-20 17:44:00'
},
productList: [
{ id: 1, productName: '商品一', stock: '12', price: '12.5', disPrice: '11' },
{ id: 2, productName: '商品二', stock: '12', price: '12.5', disPrice: '11' }
]
})
</script>
场景验证及代码解释 ✍
🔨 场景一:搜索状态下,数据修改体现到 productList

查询 商品一
,然后修改 stock
字段。此时界面绑定的是 searchProductList
而非 productList
,通过输出 productList
可以看到,数据修改体现到了表单数据中
🔨 场景二:添加数据,体现到 searchProductList

当前 productList
数据如下:
js
const formData = ref({
baseAct: {
name: '活动一',
shopName: '店铺-四叶草',
startTime: '2025-08-20 17:44:00'
},
productList: [
{ id: 1, productName: '商品一', stock: '12', price: '12.5', disPrice: '11' },
{ id: 2, productName: '商品二', stock: '12', price: '12.5', disPrice: '11' }
]
})
搜索 商品三
,是没有搜索到。此时添加一条数据商品三,界面上就显示了该商品
js
const add = () => {
const product = { id: 3, productName: '商品三', stock: '12', price: '12.5', disPrice: '11' }
formData.value.productList.push(product)
}
关键代码:往 productList 添加,而非往 searchProductList 添加
js
formData.value.productList.push(product)
而 searchProductList
是通过 computed
计算而得:
js
const searchProductList = computed(() => {
if (!key.value) return formData.value.productList
return formData.value.productList.filter(item => item.productName.includes(key.value))
})
故产生上面所说的效果:
只要修改 productList
数据,searchProductList
将能得到体现。
并且由于是向 productList
添加数据,故此时 formData
也是最新数据。
🔨 场景三:删除数据,体现到 searchProductList

这里的关键也是删除 productList
数据,searchProductList
通过 computed
计算而得。
js
const remove = (row) => {
const productList = formData.value.productList.filter((item) => item.id !== row.id)
formData.value.productList = productList
console.log('移除 formData.productList', formData.value.productList)
}
完整代码 ✍
js
<template>
<div>
<el-input v-model="key" style="margin: 12px; width: 200px;" placeholder="请输入关键字"></el-input>
<el-button @click="add">增加一条数据</el-button>
<el-table :data="searchProductList">
<el-table-column prop="productName" label="商品名称" />
<el-table-column prop="stock" label="库存数量">
<template #default="{ row }">
<el-input v-model="row.stock" @change="change"></el-input>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" />
<el-table-column prop="disPrice" label="折扣价格" />
<el-table-column prop="operation" label="操作">
<template #default="{ row }">
<el-button @click="remove(row)">移除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { computed, ref } from 'vue'
const key = ref('')
const searchProductList = computed(() => {
if (!key.value) return formData.value.productList
return formData.value.productList.filter(item => item.productName.includes(key.value))
})
const formData = ref({
baseAct: {
name: '活动一',
shopName: '店铺-四叶草',
startTime: '2025-08-20 17:44:00'
},
productList: [
{ id: 1, productName: '商品一', stock: '12', price: '12.5', disPrice: '11' },
{ id: 2, productName: '商品二', stock: '12', price: '12.5', disPrice: '11' }
]
})
const add = () => {
const product = { id: 3, productName: '商品三', stock: '12', price: '12.5', disPrice: '11' }
formData.value.productList.push(product)
}
const remove = (row) => {
const productList = formData.value.productList.filter((item) => item.id !== row.id)
formData.value.productList = productList
console.log('移除 formData.productList', formData.value.productList)
}
const change = () => {
console.log('修改 searchProductList')
console.log('表单中的 productList', formData.value.productList)
}
</script>