因为公司需要尝试新的UI框架,因此自己也是学习了iview这个新的框架,之前一直都是用的element-ui,正好公司项目用到可编辑表格这样的组件,但是网上也是搜不到相关的资料,所以自己在参考了iview-admin的一些方法之后,自己写了一个,当然这个组件还是有一些缺陷后面会说到,本篇就是记录一下自己学习新的ui框架的一个过程。

首先自己希望的可编辑的表格是这样的一种形式。

就是这样的整行可以点击编辑的样式,看似好像很简单,但是其中有非常多的坑。首先按照自己的想法,就是讲表格中显示编辑和实际数据的地方抽象出来成为一个组件

//   inputEdit.vue
<template><div><div v-if="params.column.options === 'handle'"><div v-show="editIndex !== params.index" class="handle"><Button @click="startEdit" type="default" size="small">编辑</Button><Poptip confirmtitle="确认删除"@on-ok="deleteData"><Button type="default" size="small">删除</Button></Poptip></div><div v-show="editIndex === params.index" class="handle"><Button @click="saveEdit" type="default" size="small">保存</Button><Button @click="cancelEdit" type="default" size="small">取消</Button></div></div><div class="tables-edit-outer" v-else><div class="tables-edit-con" v-show="editIndex !== params.index"><span class="value-con">{{value}}</span></div><div class="tables-editting-con" v-show="editIndex === params.index"><Input v-show="params.column.options === 'input'"v-model="params.row[params.column.key]"@on-change="handleChange":maxlength='25'placeholder="请输入内容"></Input><Select v-show="params.column.options === 'select'"v-model="params.row[params.column.key]"@on-change="handleChange"><Option v-for="(item, index) in options" :key="index" :value="item.label">{{item.value}}</Option></Select><DatePicker v-show="params.column.options === 'date'"placeholder="请选择年份"type="year":editable="editable":value="String(params.row[params.column.key])"@on-change="handleChange"></DatePicker><DatePicker v-show="params.column.options === 'dateMonth'"placeholder="请选择年月"type="month":editable="editable":value="String(params.row[params.column.key])"@on-change="handleChange"></DatePicker><DatePicker v-show="params.column.options === 'dateAll'"placeholder="请选择日期"type="date":editable="editable":value="String(params.row[params.column.key])"@on-change="handleChange"></DatePicker></div></div></div>
</template>
<script>
export default {name: 'TablesEdit',data () {return {editRow: {},editable: false}},props: {value: {required: true},params: Object,tableData: Array,options: Array,columns: Array,editIndex: [Number,String],backupsRow: Object},methods: {handleChange (e) {if (this.params.column.options === 'date' || this.params.column.options === 'dateMonth' || this.params.column.options === 'dateAll' || this.params.column.options === 'select') {this.params.row[this.params.column.key] = ereturn;}this.params.row[this.params.column.key] = e.target.valuethis.$emit('on-editing',this.params)},deleteData () {this.$emit('on-delete', this.params)},startEdit () {this.$emit('on-start-edit', this.params)this.editRow = this.params.row},saveEdit () {this.$emit('on-save-edit', this.params)this.editRow = {}},cancelEdit () {this.$emit('on-cancel-edit',this.params)}}
}
</script>

样式这里就忽略了,可以看到逻辑还是很简单的,就是根据不同的列选项,来展示相应的输入编辑框,可能很多同学看了觉得这个日期框可以复用,不用一个一个判断,当时也是这么想的,但是实现的时候发现,不同类型的日期框,显示的值也是不一样的,如果复用这个的话,父级组件上面的prop非常多,不利于这个组件的复用,而这个编辑组件其实内容还是比较少的。
搞定了这个以后,再来看整个表的结构,我们需要把这个组件放在一个表格的组件中,所以有了这样,

//   tableEdit.vue
<div class="my-edit-table"><Tableref="tablesMain"border:data="insideTableData":columns="insideColumns"><slot name="header" slot="header"></slot><slot name="footer" slot="footer"><Table v-if="showSummary" :show-header="false" :data="summaryData" :columns="summaryColumns"></Table></slot><slot name="loading" slot="loading"></slot></Table><div class="add"><Button type="default" style="width: 100%" icon="md-add" @click='addRow'>添加</Button></div></div>

博主这里是增加了一个添加行的功能,逻辑其实就是在表格数据上添加一行空数据,另外因为iview没有合计行的功能,所以博主自己也是写了一个类似element的合计行,看到这里其实我们刚刚的组件都还没有用上,别着急,其实iview的表格组件和element表格最大的区别就在于自定义方法的不同,iview是用了vue的render函数来构造的表格自定义的,而element则是将自定义的dom元素封装成了模板,拿来用就可以了,所以相比较而言,iview还是要复杂一些的。来看看我们是怎么使用我们刚刚的组件的。

//  动态渲染表格的每列的render函数suportEdit (item, index) {item.render = (h, params) => {return h(TablesEdit, {props: {params: params,value: this.insideTableData[params.index][params.column.key],tableData: this.insideTableData,options: this.options,editIndex: this.editIndex,columns: this.insideColumns,backupsRow: this.backups},on: {'on-editing': params => {this.tempSummary.splice(params.index, 1, params.row)},'on-delete': params => {this.insideTableData.splice(params.index, 1)this.tempSummary.splice(params.index, 1)if (params.row.id) {this.deleteData.push(params.row)this.$emit('delete-data',this.deleteData)} else {this.addData.splice(params.index, 1)this.$emit('add-data',this.addData)}},'on-cancel-edit': (params) => {this.editIndex = -1;if (this.isAddRow) {this.insideTableData.splice(params.index, 1)this.isAddRow = false;} else {this.insideTableData.splice(params.index, 1, this.backups)this.tempSummary = this.insideTableData.slice()}this.backups = {};this.$emit('get-save');},'on-start-edit': (params) => {if (this.editIndex !== -1) {this.$Message.warning({content: '请先保存数据'})return;}this.backups = Object.assign({}, params.row)this.editIndex = params.indexthis.$emit('not-save')},'on-save-edit': (params) => {// 验证输入let identity = this.identity.bind(this, params)if (identity()) {this.insideTableData[params.index] = params.rowif (params.row.id) {let flag = falsethis.updateData.forEach(item => {if (item.id === params.row.id) flag = true})//  设置标识,如果更新集合中的某项id等于当前编辑行的id,则表示数据并未更新,因此不添加到更新数组if (!flag) {this.updateData.unshift(params.row)}this.$emit('update-data',this.updateData)} this.editIndex = -1;if (this.isAddRow) {this.addData.push(params.row)this.$emit('add-data',this.addData)this.isAddRow = false} else if (!params.row.id) {this.addData.splice(-1, 1, params.row)this.$emit('add-data',this.addData)}this.backups = {}this.$emit('get-save')}}}})}return item},//  根据父组件传过来的列数据添加渲染函数handleColumns (columns) {this.insideColumns = columns.map((item, index) => {let res = itemif (res.children) {let child = res.childrenchild.forEach((item, index) => {item = this.suportEdit(item, index)})} else {res = this.suportEdit(res, index)}return res})},

整个逻辑其实很简单,只是非常复杂,稍不注意就可能产生了意向不到的bug,首先我们需要将父组件传过来的表格列的数组进行遍历,因为考虑到复杂表头的情况,所以我们需要深层去遍历,遍历以后,每一项执行suportEdit函数,这个函数其实就是iview当中封装的渲染函数,注意这个函数和原生的vue的渲染函数又有些不一样,上面的代码中可以看到,render函数有两个参数,一个就是我们熟悉的h渲染函数,另外一个则是一个对象params,这个params其实就是表格中的一些数据,有行数据,列数据,以及索引等等。其次我们通过this.$emit的方法,来向父组件传递一些自定义的事件,比如开始编辑,删除等按钮的事件,这个也是博主感觉不好的地方,因为数据流过于混乱,有传入子组件的数据,也有传入父组件的数据,并不是vue中倡导的单向数据流,后续维护可能会比较麻烦,因为追踪这些数据的流向可能就是一个比较大的工程,而博主这样做,也是因为公司项目中这样的表格非常多,如果每次都重复这样的组件的话,在对性能影响不多的情况,还是选择将这个组件抽象出来更好,所以如果你的项目中这样的表格并不多,还是iview每个列渲染一次就可以了。

tableEdit组件才是我们需要复用的组件,注意这里用了一些addData,updateData,deleteData这样的数组,其实就是编辑过程中,更改,增加以及删除的数据,最终是要传给服务端的,所以博主将这些数据抽离出来,最终当做参数传递给服务端,当然如果你只需要传入最终的表格数据作为参数的话,就不需要这样的一些数据。

这个组件最重要的地方,其实就是四个按钮,编辑,删除,保存,取消,这四个按钮逻辑看似简单,但是其实还是比较复杂的,首先点击编辑话,改变编辑状态editIndex,这样切换到编辑状态,同时输入数据修改的时候,要将编辑前的数据保存到临时数据backupRow中,因为每次编辑的值会传给v-model绑定的值,这样表格数据的值也会被改变了,本来没有问题,但是如果你点击了取消按钮,编辑的数据无效,但是还是改变了表格数据不就矛盾了吗,其次,当点击删除的时候,则将点击按钮的索引传递给表格数组,删除掉索引行的表格数据来实现删除,这个还是比较简单的,第三则是点击保存的时候,因为这里记录了update更新的数组,每次保存到服务端的时候,服务端会生成一个id,所以我们会判断一下update数组里面的每项的值,如果id属性相等,则表示这个数据就是之前修改的数据,就不需要将此行数据加入到update数组中,因为如果没有这样的判断的话,当你每次点击保存的时候,都会将当前行数据加入到update中,肯定不是我们想要的结果。最后取消按钮就是将编辑状态editIndex变成-1,还原成默认状态。

最后来看看合计功能的实现,合计功能就是参照了element的合计来实现的

computed: {summaryData () {let sum = {}let arr = []this.summaryColumns.forEach((column, index) => {if (index === 0) {sum.total = '合计';return;}if (column.key === 'handle' ) {sum.handle = '';return;}let values = this.tempSummary.map(item => Number(item[column.key]))//  只要values中有一个值为NaN就不进行累加计算if (!values.some(value => isNaN(value))) {sum[column.key] = values.reduce((prev, curr) => {const value = Number(curr);if (!isNaN(value)) {return prev + curr;} else {return prev;}}, 0);sum[column.key] = sum[column.key].toFixed(2);}})arr.push(sum)return arr;}},

逻辑就是我们在表格的slot里面又添加了一个table,这个table没有表头,只有数据项,我们根据主表格的数组来进行累加,用的就是reduce归并方法,不熟悉的同学可以去搜搜,然后规定第一列显示合计的字样,最后一列handle不进行操作,中间的数据项如果有一项不是数字的话,则不进行计算。当然这里考虑到普遍适用性,没有办法给每一列的合计数据添加好一个单位,所以暂时是这样,博主也是用了这样一个思路,在element上面也封装了一个近似的组件,因为这个iview的组件点击取消按钮的时候回有延迟的情况,博主研究了很久,知识有限也是没有找出原因,最后还是选择用element来封装,后续会将完整代码上传到github上面,如果对您有帮助的话,希望能不吝star。后续github地址

iview可编辑表格组件封装相关推荐

  1. LigerUI编辑表格组件单元格校验问题

    这几天在使用LigerUI(版本为1.2.2)编辑表格组件的时候,遇到几个小问题,从官方demo和api中没有找到解决的办法 问题1.从数据库查询出来的主键单元格不可编辑问题 主键单元格已经保存之前编 ...

  2. 【template写法】TS + vue3.2 + vite2 + element-plus 通用表格组件封装

    这里通用表格,和上一篇通用表单一样的(表格组件都在我博客里),配置完全可控,然后每个el-table-column 都是通过传入的数组来循环便利渲染,大部分常用实现也写在了下面,无法具体实现或需要你自 ...

  3. 微信小程序表格组件封装

    table.wxml <scroll-view class="table-wrap" scroll-x="{{true}}"> <view&g ...

  4. Jeecg Boot 2.3 里程碑版本发布,支持微服务和单体自由切换、提供新行编辑表格JVXETable

    项目介绍 JeecgBoot是一款基于代码生成器的低代码平台,开源界"小普元"超越传统商业级平台!采用前后端分离架构:SpringBoot 2.x,Ant Design&V ...

  5. 【愚公系列】2022年11月 微信小程序-表格组件使用

    文章目录 前言 一.表格组件使用 1.基础用法 1.1 代码 1.2 效果 总结 前言 移动端的页面本应该很少有table表格这样的展示.操作,但总归有这样的需求,然而平时用的vant和iview的小 ...

  6. antd4 table里面表单赋值_vue的组件化——table表格的封装

    什么是组件化--组件化是vue.js中的重要思想之一,也是vue的一个强大功能.它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用:任何的应用都可以被抽象成一个组件进行复用. ...

  7. bootstrap表格 行编辑状态_JS表格组件BootstrapTable行内编辑解决方案x-editable

    前言:之前介绍bootstrapTable组件的时候有提到它的行内编辑功能,只不过为了展示功能,将此一笔带过了,罪过罪过!最近项目里面还是打算将行内编辑用起来,于是再次研究了下x-editable组件 ...

  8. vue极简代码实现自定义可编辑行及操作按钮的Table表格组件(含源码及演示视频)

    效果图如下: 涉及到技术点包括: 父组件给子组件传值props.动态赋值 refs 对DOM进行操作,slot具名插槽的使用,插槽通过slot-scope给父组件传值 父组件代码: <templ ...

  9. js插件---JS表格组件BootstrapTable行内编辑解决方案x-editable

    js插件---JS表格组件BootstrapTable行内编辑解决方案x-editable 参考文章: (1)js插件---JS表格组件BootstrapTable行内编辑解决方案x-editable ...

最新文章

  1. 企业研发人员配备比例_企业管理人员合理配置比例
  2. optparse接受带空格的参数值时,需要加双引号
  3. 组织模式 - Introduction
  4. 前端请求后端数据的三种方式!
  5. 关于 IPv6 大规模部署,给我们带来了什么~
  6. 向导页设计_向导设计模式
  7. IDEA :windows下Hadoop报错null\bin\winutils.exe
  8. Spring框架----自动按照类型注入的Autowired注解
  9. 关于Movie Studio插入素材格式问题
  10. 前方荆棘遍地,愿砥砺前行
  11. svchost.exe 大量占用的问题
  12. app端分页 简单的分页 java
  13. 主数据管理(MDM)的一些概念
  14. windows系统使用cmd命令打开谷歌浏览器并设置用户资料方法步骤
  15. 常用的15个国外网站
  16. Ionic3项目实战
  17. 【TDengine】 TDengine时序数据库的快速入门总结
  18. 物理竞赛计算机,通过全国中学生物理竞赛,保送清华大学的学霸,读的是哪些专业?...
  19. 1.2.1 案例-IP 拨号器
  20. 知乎 android studio配置svn

热门文章

  1. oracle级联怎么设置,Oracle级联操作详解
  2. 银行测试(7)-支付测试
  3. Docker Windows桌面版安装 Windows家庭版伪装成专业版系统
  4. rimraf与windows的rmdir简单使用命令方法
  5. 拉格朗日乘数法 和 KTT条件
  6. 图灵机停机问题的不可判定性
  7. 历史经验之js个200经验收藏
  8. Linux中的虚拟机图形界面安装步骤,批量完成虚拟机硬件配置
  9. 【模电】0014 运放自激振荡和消除(补偿)
  10. project weibo