🍀实际开发中没想到 computed 在表单中还能这么使用🚀🚀

前言 ✍

业务场景:

后端会返回表单数据,其中表单数据包含列表数据。前端需要对列表数据进行增删查改。

前端处理后,最后将最新数据返回给到后端。

假设后端返回的数据结构如下:

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>
相关推荐
一 乐8 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
前端snow9 小时前
ai agent --- postgreSQL 关系型数据库
前端
卷无止境10 小时前
ECharts:把数据变成故事的可视化利器
前端
Eric_见嘉10 小时前
在职前端 Skill 和 MCP 分享
前端·后端·agent
liangshanbo121511 小时前
面试题:如何优化 Webpack 的打包速度?
前端·webpack·node.js
wengad11 小时前
从 wangEditor 迁到 wangEditor-next
前端·javascript·vue.js
行者-全栈开发12 小时前
【前端/JS框架】CVE-2026-3854:GitHub Enterprise Server X-Stat注入XSS漏洞深度剖析与紧急修复指南
前端·javascript·github
计算机魔术师13 小时前
AMD砸82亿买下李飞飞,这次不卖芯片卖什么?
前端
hzxpaipai13 小时前
杭州企业官网怎么建设?从策划到上线的5步建站方法
运维·服务器·前端·网络
怕浪猫13 小时前
2026年金九银十,我面了22个前端
前端·javascript·面试