ant design vue嵌套表格及表格内部编辑的用法说明


Posted in Javascript onOctober 28, 2020

实现效果:

ant design vue嵌套表格及表格内部编辑的用法说明

因为pro手脚架中封装的s-table不支持expand和expandedRowsChange事件,无法实现根据展开节点获取其内部数据的需求,因此直接使用a-table组件

表格外层可以翻页,查询携带页码参数

<a-table
size="default"
rowKey="dict_id" //根据自己数据内部关键针设定
ref="table"
@expandedRowsChange="expandedRowsChange"
@expand="expand" // 展开表格节点操作
@change="change" // 外层表格中排序,翻页,修改页面数量等操作
:expandedRowKeys="expandedRowKeys" // 操作展开的节点
:pagination="pagination" // 页码参数
:columns="columns" // 表头
:dataSource="loadData" // 数据
>
<a-table
size="default"
style="margin-bottom:0;"
rowKey="key"
slot="expandedRowRender" // 以内层方式展现
:columns="innerColumns"
:dataSource="data"
:pagination="false"
:loading="innerloading"
@change="innerhandleChange"
>
<template v-for="(col, i) in ['item_text', 'item_value', 'item_checked', 'item_remark', 'item_sort', 'item_status']" :slot="col" slot-scope="text, record">
<a-input
:key="col"
v-if="record.editable"
style="margin: -5px 0"
:value="text"
:placeholder="innerColumns[i].title"
@change="e => handleChange(e.target.value, record.key, col)"
/>
<template v-else>{{ text }}</template>
</template> // 内部表格可编辑模板
<template slot="operation" slot-scope="text, record">
<template v-if="record.editable">
<span v-if="record.isNew">
<a @click="saveRow(record)">添加</a>
<a-divider type="vertical" />
<a-popconfirm title="是否要删除此行?" @confirm="remove(record.key)">
<a>删除</a>
</a-popconfirm>
</span>
<span v-else>
<a @click="saveRow(record)">保存</a>
<!-- <a-divider type="vertical" />
<a @click="cancel(record.key)">取消</a> -->
</span>
</template> // 内部表格新增模板
<span v-else>
<a @click="toggle(record)">编辑</a>
</span>
</template>
</a-table>
<div
slot="expandedRowRender"
style="margin: 0">
<a-button style="width: 100%; margin-top: 16px; margin-bottom: 8px" type="dashed" icon="plus" @click="newMember">新增属性</a-button>
</div>
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
</span>
</a-table>

主要数据:

expandedRowKeys: [],
  // 表头
  columns: [
  {
   title: '字典编码',
   dataIndex: 'dict_code'
  },
  {
   title: '字典名称',
   dataIndex: 'dict_name'
  },
  {
   title: '状态',
   dataIndex: 'dict_status'
  },
  {
   title: '字典描述',
   dataIndex: 'dict_remark'
  }, {
   title: '操作',
   width: '150px',
   dataIndex: 'action',
   scopedSlots: { customRender: 'action' }
  }
  ],
  loadData: [],
  innerColumns: [
  {
   title: '字段名',
   dataIndex: 'item_text',
   key: 'item_text',
   width: '15%',
   scopedSlots: { customRender: 'item_text' }
  },
  {
   title: '字段值',
   dataIndex: 'item_value',
   key: 'item_value',
   width: '15%',
   scopedSlots: { customRender: 'item_value' }
  },
  {
   title: '默认选中(0:否,1:是)',
   dataIndex: 'item_checked',
   key: 'item_checked',
   width: '10%',
   scopedSlots: { customRender: 'item_checked' }
  },
  {
   title: '备注',
   dataIndex: 'item_remark',
   key: 'item_remark',
   width: '20%',
   scopedSlots: { customRender: 'item_remark' }
  },
  {
   title: '排序号',
   dataIndex: 'item_sort',
   key: 'item_sort',
   width: '10%',
   sorter: true,
   scopedSlots: { customRender: 'item_sort' }
  },
  {
   title: '状态(1:正常,2:异常)',
   dataIndex: 'item_status',
   key: 'item_status',
   width: '10%',
   scopedSlots: { customRender: 'item_status' }
  },
  {
   title: '操作',
   key: 'action',
   scopedSlots: { customRender: 'operation' }
  }
  ],
  data: [],
  innerloading: false,
  parameter: {
  pageNo: 1,
  pageSize: 10
  },
  // 排序参数
  sortedInfo: null,
  pagination: {
  total: 1,
  current: 1,
  showTotal: total => `共 ${total} 条记录 第 ${this.pagination.current} / ${Math.ceil(total / this.pagination.pageSize)} 页`,
  showQuickJumper: true,
  showSizeChanger: true,
  pageSize: 10
  }

初始进入页面时,需要获取外层表格

使用初始参数parameter请求第一页数据,从返回数据中对pagination重置翻页组件内部参数,主要有当前页,页码总量,页码大小

getDictList(this.parameter)
  .then(res => {
   if (res.code === '200') {
   console.log(res)
   this.loadData = res.data
   this.pagination.total = res.totalCount
   this.pagination.current = res.pageNo
   this.pagination.pageSize = res.pageSize
   } else {
   this.$message.error(res.message)
   }
  })

展开外层数据节点获取内部数据:

expand (expanded, record) {
  this.expandedRowKeys = [] // 重置展开节点,只展开当前点击的节点(内部数据调用模板,无法做到同时几个内层表格数据直接缓存在页面)
  if (expanded) {
  this.expandedRowKeys = [record.dict_id]
  this.getDictItem() // 获取表格内部数据
  }
  console.log(expanded, record)
 },
// 展开节点后获取内部表格数据
getDictItem (obj) {
  let searchparam = { dict_id: this.expandedRowKeys[0] }
  if (obj) { // 内部表格除了根据其父节点id查找的条件外,还支持排序,因此需要整合排序参数
  searchparam = Object.assign(searchparam, obj)
  }
  this.innerloading = true
  getDictItemList(searchparam).then(res => {
  if (res.code === '200') {
   this.data = res.data
   this.innerloading = false
  } else {
   this.$message.error(res.message)
  }
  })
 },
// 外层表格操作
 change (pagination, filters, sorter) { // 对页面大小,筛选,排序等条件修改后重新查询数据
  this.pagination = pagination
  this.parameter.pageNo = pagination.current
  this.parameter.pageSize = pagination.pageSize
  this.getDict()
  console.log('pagination', pagination)
  console.log('filters', filters)
  console.log('sorter', sorter)
 },
 /* 内层表格操作 */
 innerhandleChange (pagination, filters, sorter) {
  console.log('Various parameters', pagination, filters, sorter)
  this.sortedInfo = {
  sortField: sorter.field,
  sortOrder: sorter.order
  }
  this.getDictItem(this.sortedInfo)
 },

至此,展示功能已经几乎做完啦,现在是内部表格的编辑与新增功能

handleChange (value, key, column) { // 实时更新表格中各个输入框的状态
  const newData = [...this.data]
  const target = newData.filter(item => key === item.key)[0]
  if (target) {
  target[column] = value
  this.data = newData
  }
 },
 toggle (data) { // 切换输入框与文本状态,实现展示与编辑功能
  const target = this.data.filter(item => item.key === data.key)[0]
  target.editable = !target.editable
  console.log(this.data)
 },
 newMember () { // 新增内容后的数据字段
  this.data.push({
  'item_text': '',
  'item_value': '',
  'item_checked': '',
  'item_remark': '',
  'item_sort': '',
  'item_status': '',
  key: this.data.length,
  editable: true,
  isNew: true
  })
 },
 saveRow (record) {
  this.innerloading = true
  if (!record.item_text || !record.item_value) { // 对必填项进行管控
  this.innerloading = false
  this.$message.error('请至少填写填写字段名和字段值。')
  return
  }
  record.item_checked = record.item_checked || 0 // 设置默认值
  record.item_sort = record.item_sort || 1
  record.item_status = record.item_status || 1
  record.dict_id = this.expandedRowKeys[0]
  if (record.item_id) { // 修改
  updateItem(record).then(res => {
   if (res.code === '200') {
   this.$message.success(res.message)
   this.getDictItem() // 修改成功后重新获取当前内部表格数据
   } else {
   this.$message.error(res.message)
   }
  })
  } else {
  addItem(record).then(res => {
   if (res.code === '200') {
   this.$message.success(res.message)
   this.getDictItem()
   } else {
   this.$message.error(res.message)
   }
  })
  }
 },
 cancel (key) {
  const target = this.data.filter(item => item.key === key)[0]
  target.editable = false
 },
 remove (key) {
  const newData = this.data.filter(item => item.key !== key)
  this.data = newData
 },
 /* 内层表格操作结束 */

外层表格与内存表格数据示例:

{
 "success": true,
 "code": "200",
 "message": "分页查询成功",
 "data": [{
 "dict_id": 1,
 "dict_code": "common_org_type",
 "dict_name": "机构类别",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": "机构类别"
 }, {
 "dict_id": 2,
 "dict_code": "common_user_type",
 "dict_name": "人员类别",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": "人员类别"
 }, {
 "dict_id": 48,
 "dict_code": "cdsfcsdcf",
 "dict_name": "修改属性1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": ""
 }, {
 "dict_id": 49,
 "dict_code": "bugbugbug",
 "dict_name": "有字典id",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": ""
 }, {
 "dict_id": 50,
 "dict_code": "1",
 "dict_name": "名称",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": "1"
 }, {
 "dict_id": 51,
 "dict_code": "1",
 "dict_name": "1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": null
 }, {
 "dict_id": 52,
 "dict_code": "1",
 "dict_name": "1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": null
 }, {
 "dict_id": 53,
 "dict_code": "1",
 "dict_name": "1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": null
 }, {
 "dict_id": 54,
 "dict_code": "1",
 "dict_name": "1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": ""
 }, {
 "dict_id": 55,
 "dict_code": "dbhasuiuh",
 "dict_name": "测试字典1",
 "dict_pid": null,
 "dict_status": 1,
 "dict_remark": "备注"
 }],
 "totalCount": 11,
 "pageNo": 1,
 "pageSize": 10,
 "totalTag": 1
}
{
 "success": true,
 "code": "200",
 "message": "查询成功",
 "data": [{
 "item_id": 2,
 "dict_id": 1,
 "item_text": "外部",
 "item_value": "2",
 "item_status": 1,
 "item_sort": 2,
 "item_remark": null,
 "item_checked": 1,
 "editable": 0 // 写死就行了 一定要有 用于内部表格编辑功能
 }, {
 "item_id": 1,
 "dict_id": 1,
 "item_text": "内部",
 "item_value": "1",
 "item_status": 1,
 "item_sort": 1,
 "item_remark": "1",
 "item_checked": 1,
 "editable": 0
 }]
}

补充知识:ant design Table可编辑的单元格改进版

antd官方也有给文档,但是超级麻烦,代码量还超级多,改编了一下

如图:

ant design vue嵌套表格及表格内部编辑的用法说明

这里table的columns的写法,如下:

const columns2 = [
{
title: '尺寸名称',
dataIndex: 'name',
filterDropdown: true,
filterIcon: <Icon type="edit"/>,
render: () => <Input />,
},
{
title: '标准尺寸',
dataIndex: 'standard',
filterDropdown: true,
filterIcon: <Icon type="edit"/>,
render:() => <Input />,
},
{
title: '上偏差',
dataIndex: 'upper_deviation',
filterDropdown: true,
filterIcon: <Icon type="edit"/>,
render:() => <Input />,
},
{
title: '下偏差',
dataIndex: 'lower_deviation',
filterDropdown: true,
filterIcon: <Icon type="edit"/>,
render: () => <Input />,
},
{
title: '工序',
dataIndex: 'procedure',
filterDropdown: true,
filterIcon: <Icon type="edit"/>,
render: () => 
<Select>
  <Option value='1'>1</Option>  
  <Option value='2'>2</Option> 
</Select>
},
{
title: '操作',
dataIndex: 'operation',
render: (text, record) => (
this.state.size.length >= 1
? (
<Popconfirm title="确定删除该信息?" onConfirm={() => this.handleDelete(record.key)}>
<a href="javascript:;">删除</a>
</Popconfirm>
) : null
),
}
];

其中

filterDropdown: true,

filterIcon: <Icon type="edit"/>,

这两个是用于给表头添加图标,不需要可以不写

实现可编辑表格最重要的是吧这个表格所有字段都变成可控字段,这样就可以实现对表格数据的提交的基本操作

就拿我这里面的尺寸名称来说,这个字段叫name ,这里的render就要修改成render: (text, record) => <Input value={text} onChange={(e) => this.handleChange({name: e.target.value}, record)}/>,

这里参数text可以理解为 input的初始值,onChange事件是吧这个input变成可控的组件,handleChange这里有两个参数,这里“”name: e.target.value“”必须要这么传,目的是把改组件的值跟name进行绑定。

handleChange 方法

handleChange = (value, record) => {
for (var i in value) {
record[i] = value[i];//这一句是必须的,不然状态无法更改
this.setState({
size: this.state.size.map((item, key) => item.key == record.key ? {...item, [i]: value[i]} : item)
})
}
}

这里我把这个可编辑表格的值存在state中的size中,通过key进行匹配(这里key代表我这个表格的rowkey,也就是用来区分行数据的一个标识),然后修改指定行的指定数据,通过改变state中的size更新视图,同时吧更改的数据替换掉原来的 这就实现了对表格数据的实时监听,同时表格的所有数据存在了state中的size中,想要获取表格数据直接用this.state.size即可。

(这里需要注意的时,如果把表格中的某个字段,比如说name设置成表格的rowkey,就会发生name字段只能输入单个字符就会失去焦点的情况)

以上这篇ant design vue嵌套表格及表格内部编辑的用法说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript异步编程的4种方法让你写出更出色的程序
Jan 17 Javascript
JQuery对class属性的操作实现按钮开关效果
Oct 11 Javascript
判断在css加载完毕后执行后续代码示例
Sep 03 Javascript
javascript实现的固定位置悬浮窗口实例
Apr 30 Javascript
总结javascript中的六种迭代器
Aug 16 Javascript
VueJs路由跳转——vue-router的使用详解
Jan 10 Javascript
深入理解React Native原生模块与JS模块通信的几种方式
Jul 24 Javascript
node vue项目开发之前后端分离实战记录
Dec 13 Javascript
讲解vue-router之什么是动态路由
May 28 Javascript
脚手架vue-cli工程webpack的基本用法详解
Sep 29 Javascript
用Object.prototype.toString.call(obj)检测对象类型原因分析
Oct 11 Javascript
vue与iframe之间的信息交互的实现
Apr 08 Javascript
解决ant design vue 表格a-table二次封装,slots渲染的问题
Oct 28 #Javascript
ant design vue中表格指定格式渲染方式
Oct 28 #Javascript
vue实现一个矩形标记区域(rectangle marker)的方法
Oct 28 #Javascript
ant design vue datepicker日期选择器中文化操作
Oct 28 #Javascript
微信小程序picker组件两列关联使用方式
Oct 27 #Javascript
解决ant Design中this.props.form.validateFields未执行的问题
Oct 27 #Javascript
解决antd Form 表单校验方法无响应的问题
Oct 27 #Javascript
You might like
ThinkPHP实现多数据库连接的解决方法
2014/07/01 PHP
PHP文件操作方法汇总
2015/07/01 PHP
浅谈thinkphp5 instance 的简单实现
2017/07/30 PHP
定位地理位置PHP判断员工打卡签到经纬度是否在打卡之内
2019/05/23 PHP
PHP中的自动加载操作实现方法详解
2019/08/06 PHP
checkbox 复选框不能为空
2009/07/11 Javascript
JS自动适应的图片弹窗实例
2013/06/29 Javascript
Javascript核心读书有感之语句
2015/02/11 Javascript
浅谈关于JavaScript API设计的一些建议和准则
2015/06/24 Javascript
玩转JavaScript OOP - 类的实现详解
2016/06/08 Javascript
JSONP基础知识详解
2017/03/19 Javascript
webpack2.0配置postcss-loader的方法
2017/08/17 Javascript
移动端Ionic App 资讯上下循环滚动的实现代码(跑马灯效果)
2017/08/29 Javascript
微信小程序获取手机系统信息的方法【附源码下载】
2017/12/07 Javascript
使用vue-route 的 beforeEach 实现导航守卫(路由跳转前验证登录)功能
2018/03/22 Javascript
Vue微信项目按需授权登录策略实践思路详解
2018/05/07 Javascript
浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用
2020/03/08 Javascript
快速解决vue2+vue-cli3项目ie兼容的问题
2020/11/17 Vue.js
[01:09:19]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第二场 2月28日
2021/03/11 DOTA
python用ConfigObj读写配置文件的实现代码
2013/03/04 Python
浅谈Python黑帽子取代netcat
2018/02/10 Python
python selenium执行所有测试用例并生成报告的方法
2019/02/13 Python
决策树剪枝算法的python实现方法详解
2019/09/18 Python
python深copy和浅copy区别对比解析
2019/12/26 Python
python中68个内置函数的总结与介绍
2020/02/24 Python
详解HTML5 LocalStorage 本地存储
2016/12/23 HTML / CSS
英国最大的体育&时尚零售公司:JD Sports
2017/12/13 全球购物
西班牙Polo衫品牌:Polo Club
2020/08/09 全球购物
Java的基础面试题附答案
2016/01/10 面试题
销售员自我评价怎么写
2013/09/19 职场文书
开业庆典邀请函
2014/01/08 职场文书
公司承诺书范文
2014/05/19 职场文书
大学教师师德师风演讲稿
2014/08/22 职场文书
2015年小学图书室工作总结
2015/05/18 职场文书
python自动统计zabbix系统监控覆盖率的示例代码
2021/04/03 Python
详解Python函数print用法
2021/06/18 Python