vxe-table可编辑表格实战:增删改查与必填校验全解析

发布时间:2026/10/1 4:25:56
vxe-table可编辑表格实战:增删改查与必填校验全解析 搞后台管理系统最磨人的就是表格那一摊子事。尤其是那种用户直接在格子里面改数据的需求你以为是省事了结果做起来全是细节。vxe-table这个组件库我从两个项目之前开始用一开始也就是图它快后来越用越觉得它在可编辑表格这块儿是下了功夫的。今天这篇就把我用vxe-table做可编辑表格、实现增删改查和必填校验的完整过程拆开聊从设计思路到踩坑点尽量说透。这篇文章适合谁看主要是给那些用Vue做中后台项目、正在纠结要不要自己用input table拼一个可编辑表格的同仁。同时也适合已经摸过vxe-table但卡在校验、增删行这些细节上的人。我会先把核心思路讲清楚再给完整步骤和代码最后把我在真实项目里踩过的坑和优化经验列出来你直接照着抄能少走不少弯路。1. 动手之前先想清楚需求和方案1.1 为什么选vxe-table而不是自己拼表格很多朋友一上来就选择用el-table或者原生table再加一堆input去拼说实话数据少的时候还能忍等数据量上来或者校验规则复杂起来你会有一种所有状态都得自己管的无力感。你要维护哪些单元格处于编辑态、哪些校验没通过、哪些数据变更过、保存时要收集哪些数据——这些东西叠加在一起代码很快就失控了。vxe-table的好处在于它在组件层面就把可编辑这个能力做成了原生功能。你不用自己监听每个input的change事件不用手动给每个单元格加编辑状态也不需要一个个绑校验字段。它有一种edit-config的配置方式配合列上的edit-render和edit-rules能直接把整个表格变成一个表单。这意味着适配器、状态管理、校验体系它全给你内置好了。1.2 这个项目的最小闭环是什么这个项目标题虽然就几个字但拆开看其实是四个相互独立又彼此关联的能力增新增一行或者多行数据从空状态变成可编辑状态。删删除选中的行同时要和后端数据保持同步。改直接在单元格里改内容相当于替代了传统的表单编辑页面。查查询后端数据并回显到表格且保证数据格式和列配置匹配。必填校验比如姓名手机号金额这些字段不能空着提交时统一校验。这里有个很多人容易漏掉的点这四项操作不是各做各的而是共用一个表格实例和数据源。你新增一行表格要进入可编辑状态你点击保存要给整张表做校验校验不过要能准确定位到具体哪个格子。所以方案设计的第一原则就是数据和状态要收敛在组件内部而不是散落在一堆ref和watcher里面。1.3 功能结构拆解我用一张思维导图式的结构来规划虽然没有图但逻辑是这么理的表格配置层列配置columns、编辑配置editConfig、校验规则editRules数据层tableData前端数据源操作层新增、删除、保存、查询这些方法反馈层校验不过的提示、删除确认、操作结果的toast这个结构界定清楚之后后面写代码就不用东一榔头西一棒子了。2. 从零搭一个能用的vxe-table基础表格2.1 安装与引入先说我用的环境Vue 2 vxe-table 3.x这个组合比较成熟文档也最全。如果你用Vue 3那对应的是vxe-table 4.xAPI风格差异不大但个别配置名有变化我文中的写法以3.x为主。npm install vxe-table3在main.js里全局引入import Vue from vue import VXETable from vxe-table import vxe-table/lib/style.css Vue.use(VXETable)这里有个小建议如果你只是用表格其实可以不用全量引入按需引入更省打包体积。但项目里如果表格用得多直接全局引入反而省心因为按需引入要用到babel插件配置起来也是一个成本。我一般是在工具类和组件库之间做一个平衡UI组件按需表格这种重度使用的就全局引。2.2 列配置和数据源绑定vxe-table的核心是columns配置。我把数据定义成响应式的export default { data() { return { tableData: [], columns: [ { type: checkbox, width: 50 }, { type: seq, title: 序号, width: 60 }, { field: name, title: 姓名, minWidth: 140 }, { field: mobile, title: 手机号, minWidth: 160 }, { field: age, title: 年龄, minWidth: 100 }, { field: amount, title: 金额, minWidth: 140 }, { field: remark, title: 备注, minWidth: 200 } ] } } }然后模板vxe-table refxTable :datatableData :columnscolumns border show-overflow :edit-config{ trigger: click, mode: cell, showStatus: true } template #edit_name{ row } vxe-input v-modelrow.name / /template /vxe-table先解释一下edit-config这几个参数trigger触发编辑的方式click是点击单元格进入编辑dblclick是双击。大部分业务场景用click更顺手。modecell表示按单元格维度编辑还有row是整行编辑。按单元格编辑更灵活但校验粒度也更细。showStatus开启之后变更过的单元格左侧会有一个小标记这个在视觉上非常有用用户能一眼看出来这一行被改过。2.3 别忽略列和模板的对应关系在vxe-table里如果你要让某个列可编辑必须在columns里也配好对应的render或者在模板里写同名slot。我踩过的一个坑是columns里配了field: name但模板里忘了写#edit_name结果点击单元格进去只能看到纯文本根本没法输入。这俩必须配套缺一个vxe-table就退化成只读表格。如果你不想在模板里写太多slot也可以直接在columns里用editRender的方式{ field: name, title: 姓名, minWidth: 140, editRender: { name: input } }这种方式更简洁适合输入框这种单一控件。但如果校验或联动逻辑复杂还是在模板里写slot更灵活、可读性更高。3. 必填校验别让用户蒙着头提交3.1 edit-rules怎么配校验是编辑表格最有价值的点。vxe-table提供了specific-config校验方案你只需要在columns里配上editRules或者在表格级别用edit-config里的rules统一配。我习惯把规则直接写在columns的每一项上这样每个字段的校验职责是内聚的columns: [ { field: name, title: 姓名, minWidth: 140, editRender: { name: input }, editRules: [ { required: true, message: 姓名不能为空 }, { min: 2, max: 10, message: 姓名长度在2到10个字符之间 } ] }, { field: mobile, title: 手机号, minWidth: 160, editRender: { name: input }, editRules: [ { required: true, message: 手机号不能为空 }, { pattern: /^1[3-9]\d{9}$/, message: 手机号格式不正确 } ] } ]这里有个直观的体会校验规则写在columns里等于你把这张表长什么样和这张表怎么才能合法放在了一起。后面改需求时只要找到那列改起来非常顺手。3.2 手动触发整表校验光配好规则还不够提交时必须手动校验。vxe-table的实例方法validate()会遍历当前所有处于编辑模式的字段并返回一个Promiseasync handleSave() { const $table this.$refs.xTable const errMap await $table.validate().catch(err err) if (errMap) { this.$XModal.message({ message: 请先修改表单中标记的错误项, status: error }) return } // 校验通过走保存逻辑 await saveApi() }这里validate()返回的如果是一个errMap对象说明有校验失败项如果是true或undefined说明通过了。不同版本返回值可能不太一样我建议你在项目里先打印一下看看再写后续逻辑别想当然。3.3 校验时机什么时候该触发很多初学者只在点保存的时候才校验导致用户体验很差——用户填了半天最后保存时才被告知一堆错误。我一般会做两个层面的校验失焦校验每个单元格编辑完成、光标离开时触发单行或单列校验。vxe-table支持在edit-closed事件里去校验当前行。提交校验保存时全表校验。单行校验的写法handleEditClosed({ row }) { this.$refs.xTable.validateRow(row).then(() { // 当前行校验通过 }).catch(() { // 当前行校验失败不用处理错误样式会自动标红 }) }综合体验下来失焦校验能即时反馈提交校验兜底这套组合是最舒服的。3.4 自定义校验的扩展技巧内置的required、pattern、min/max其实已经覆盖了大部分场景。但业务里总有恶心需求比如金额必须大于0且小于100000、备注不能超过50字且不能带特殊字符。这时候用validator自定义校验函数{ field: amount, title: 金额, editRules: [ { required: true, message: 金额不能为空 }, { validator: ({ cellValue }) { if (Number(cellValue) 0 || Number(cellValue) 100000) { return new Error(金额需在0到100000之间) } return true } } ] }这个validator接收一个对象你可以拿到cellValue、row、column等上下文非常灵活。注意返回值合法返回true不合法返回new Error(提示信息)不要返回字符串因为vxe-table内部会自己组装错误对象。4. 增删改查的实现细节4.1 新增行别只是push一条空数据新增行最容易犯的错是只往数组里push一条空对象然后发现表格能编辑但保存时所有字段都是undefined。我建议在新增时就为行数据塞好默认值并给一个临时的唯一标识方便后面删除和保存操作对应到具体行handleAddRow() { const newRow { id: Date.now(), // 临时id方便前端区分 name: , mobile: , age: null, amount: null, remark: , _isNew: true // 标记是新增的行提交时区分新增还是修改 } this.tableData.push(newRow) // 让新增的行滚动到可视区并且第一个可输入单元格处于编辑状态 this.$nextTick(() { this.$refs.xTable.setCurrentRow(newRow) }) }这种默认值的处理后面保存接口要区分新增和修改时就只需要看_isNew标记了非常省事。4.2 删除行确认弹窗是底线删除操作建议加确认弹窗。我在前一个项目里就遇到过用户手滑点错行又没有确认步骤一下子删掉一整条业务数据的情况。vxe-table有配套的VXETable.modal可以这么写handleDeleteRows() { const $table this.$refs.xTable const selectRecords $table.getCheckboxRecords() if (!selectRecords.length) { this.$XModal.message({ message: 请先勾选要删除的数据, status: info }) return } this.$XModal.confirm(确定删除选中的 ${selectRecords.length} 条数据吗).then(() { // 前端先删提交时再批量删除 selectRecords.forEach(row { const idx this.tableData.indexOf(row) if (idx -1) { this.tableData.splice(idx, 1) } }) }).catch(() {}) }有一点要特别提醒如果表格数据是分页的删除最后一行后当前页可能为空这时候应该跳回上一页或者刷新列表。这个细节很多人会漏我后面也专门踩过这个坑。4.3 修改与保存提交前做一次数据快照保存是整个增删改查的核心出口。你不能只把tableData原样丢给后端毕竟表格里可能混着新增的行、删除的行、修改的行。我的习惯是把操作分类差异化提交async handleSave() { const $table this.$refs.xTable const errMap await $table.validate().catch(err err) if (errMap) { return } const newList [] const updateList [] const deleteList [] this.tableData.forEach(row { if (row._isNew) { newList.push(this.formatRow(row)) } else { updateList.push(this.formatRow(row)) } }) // 这里deleteList是之前收集的待删除行 const params { newList, updateList, deleteList } await saveApi(params) this.$XModal.message({ message: 保存成功, status: success }) this.refreshTable() }这里值得注意的一个细节是formatRow——很多字段在表格里是字符串但后端要的是数字比如年龄、金额。提交前统一做一次类型转换能避免后端接口报参数类型错误这种问题。权衡之下在前端做一个简单的format比交给后端判断要快得多。4.4 查询数据回显时处理格式问题查询的话一般就是请求接口拿到数据后赋值给tableDataasync handleQuery() { const params { keyword: this.keyword, pageNo: this.pageNo, pageSize: this.pageSize } const res await getListApi(params) this.tableData res.data.records }但这里有个容易忽略的点回显的数据里如果某些字段是null或undefined直接显示在可编辑单元格里有时会报错或者显示很丑。比如金额是nullvxe-input在绑定时正常但如果你用了输入框的typenumbernull值会导致显示为空。我的做法是在接口返回后做一次数据归一化res.data.records.forEach(row { row.amount row.amount null ? : row.amount row.age row.age null ? null : row.age row._isNew false })这一点非常实用不然你会发现明明数据有值编辑时却怪怪的。5. 实战排坑与优化建议5.1 表格数据量大时的性能优化vxe-table本身性能已经不错但那个是建立在合理使用的前提下。如果你在可编辑表格里放了一堆实时更新的状态或者用很深的对象引用照样会卡。我总结了三招大数据量时开启虚拟滚动在表格上配置scroll-y{ enabled: true, gt: 200 }当行数超过200条时启用纵向虚拟滚动不然几千行数据直接渲染浏览器直接掉帧。避免在模板里写复杂方法调用比如{{ formatTime(row.date) }}这种每一行渲染时都会重新执行数据一多性能立刻变差。尽量在数据源里提前格式好。校验规则别太频繁触发validator里如果做了异步接口调用等于每次失焦都会请求一次这很危险。异步校验要做好防抖或者只在提交时做。5.2 保存后刷新表格的时机提交成功之后如果是在弹窗里的场景我一般直接关闭弹窗并让父组件刷新列表如果是在页面里的场景则重新请求当前分页数据。这里有个心得刷新完数据后要把tableData重新指向一个全新的数组不要在原有数组上push或修改相同引用否则vxe-table内部的一些状态比如哪些行处于选中状态不会被正确重置。this.tableData [...res.data.records]而不是this.tableData.splice(0, this.tableData.length, ...res.data.records)后者的写法在某些版本中会导致残留编辑状态或选中状态。5.3 校验错误信息的位置优化vxe-table默认的错误提示是显示在单元格下方如果表格行高比较矮可能显示不全。我调整过两个地方一个是在edit-config里设置activeMethod控制某些单元格不可编辑另一个是给表格加class-nameeditable-table然后自定义错误提示的样式比如让提示内容往上弹出而不是往下遮挡。.editable-table .vxe-cell--invalid { background: #fef0f0; }这个类名可以自定义调底色、加边框都行。用户体验上错误提示要有但不能太炸一个浅红色背景加上一行小字提示就够了。5.4 常见报错自查表这里列几个我遇到过的比较典型的报错和解决办法现象可能原因解决办法点击单元格进入不了编辑状态没配edit-config或列上没有对应editRender/slot检查表格是否配了edit-config列上是否配了editRender或同名slot校验不生效editRules没写在对应列配置上或字段名对不上确认field和editRules所在的列是同一列保存后表格显示旧数据没有重新赋值新数组引用刷新后用this.tableData [...res.data]整体替换新增的行不显示编辑控件新增的行里没有对应字段属性push数据时给字段都赋好默认值validate返回undefined但表单明明有错校验规则没生效或者没有触发校验的字段处于可见范围检查是否有列字段没有配置editRender有时纯文本列不参与校验这些基本都是配置不全或者字段对不上导致的只要你把columns、editRender、editRules这三者的字段名对齐绝大多数问题都能解决。5.5 交互细节打磨让可编辑表格更像表单表格一旦可编辑用户对保存的心理预期就和普通表单一样。所以有几个交互细节值得做保存成功后给一个明确的成功提示并且清空选中状态。表格底部固定一行按钮栏显示新增删除保存不需要用户自己滚动到页面顶部去找按钮。删除和保存在高风险操作时加loading防止用户连点多次提交。可编辑列的表头加一个视觉标记比如星号或必填小标签这样用户一进页面就知道哪些字段不能空。vxe-table的表头可以直接用slots自定义我通常会加一个红色小星号。这些细节不复杂但做了之后测试和用户都会觉得这表格确实做完整了而不是能用但很糙。根据我自己做过的几个中后台项目的经验vxe-table的可编辑表格在功能层面已经能覆盖掉80%的表格里直接改数据的场景剩下的20%基本要靠对业务的理解和交互细节去补。如果你第一次接触它我建议不要上来就追求把所有能力一次性用完先把这个最小闭环跑通基础表格 - 列配置 - 可编辑单元格 - 必填校验 - 保存提交。跑通之后再慢慢加复杂特性比如动态列、行拖拽、跨行合并这些你会发现vxe-table的能力其实远超你的预期。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询