在ant上的table常见用法是一行的元素可编辑,如下:
但是现在有一个需求是全部单元格均可编辑,如何实现呢?
- 表格组件
<a-table v-if="query.personnel_type === '0'" size="middle" row-key="id" :scroll="{ x: 'max-content' }" :columns="columns" :data-source="data" :loading="loading" :pagination="false" />
复制
- 表头数据
{ title: '月份', width: 170, dataIndex: 'created_at', }, { title: '基础员工(个)', width: 120, dataIndex: 'basic', }, { title: '高技能员工(个)', width: 120, dataIndex: 'senior', }, { title: '专业专家(个)', width: 120, dataIndex: 'expert', }, { title: '实习生(个)', width: 120, dataIndex: 'trainee', },
复制
- 效果
- 使用
<Input>
插槽可以Table组件内部渲染样式
在Table的Api第一行就显示的是具名插槽,使用这个插槽可以对表格内部数据个人化操作。
text, record, index, column
分别表示单元格的文本数据,一行的数据,索引和列的表头元素。一般情况下通过v-if
判断表头元素对该列做个性化。
- 具名插槽编辑
<a-table v-if="query.personnel_type === '0'" size="middle" row-key="id" :scroll="{ x: 'max-content' }" :columns="columns" :data-source="data" :loading="loading" :pagination="false" > <template #bodyCell="{ record, column }" > <template v-if="column.dataIndex === 'senior'" > <a-input :placeholder="record[column.dataIndex]" @change="(e) => handleChange(e.target.value, record, column)" /> </template> </template> </a-table>
复制
关键代码
<template #bodyCell="{ record, column }" > <template v-if="column.dataIndex === 'senior'" > <a-input :placeholder="record[column.dataIndex]" @change="(e) => handleChange(e.target.value, record, column)" /> </template> </template>
复制
v-if="column.dataIndex === 'senior'"
判断表头是senior元素将其变成一个input输入框,效果如下:
- 实现全单元格编辑
对所需要全局编辑的表头做判断即可,如下:
<template #bodyCell="{ record, column }" > <template v-if="['basic', 'senior', 'expert', 'trainee'].includes(column.dataIndex)" > <a-input :placeholder="record[column.dataIndex]" @change="(e) => handleChange(e.target.value, record, column)" /> </template> </template>
复制
改造后就得到了除时间外全部单元格都可编辑的一个Table,但是在默认情况下并不比想要其展现可编辑状态,而是在点击某个按钮后显示可编辑状态。
- 编辑状态改变
基于该方式我们可以在输入框添加一个v-if
判断
<a-input v-if="isShowGlobalEdit" :placeholder="record[column.dataIndex]" @change="(e) => handleChange(e.target.value, record, column)" />
复制
在默认情况下就是忽略了input
插槽。
设置按钮绑定响应事件
// 全单元格编辑 isShowAllEdit() { this.isShowGlobalEdit = true }, cloneAllEdit() { this.isShowGlobalEdit = false },
复制
这里情况下肯会不成功,应为表格已经渲染了,这时候再去改变
if
的状态已经无效了。这里有两种实现方法,第一种就是vue的钩子函数,把isShowGlobalEdit
在beforeUpdate()
重新赋值一下使表格重新渲染就可以了。另一种如下:
import { cloneDeep } from 'lodash/lang' // 全单元格编辑 isShowAllEdit() { this.isShowGlobalEdit = cloneDeep(this.isShowGlobalEdit === true) }, cloneAllEdit() { this.isShowGlobalEdit = cloneDeep(this.isShowGlobalEdit === false) },
复制
使用这种深度监听也可以实现,这个可以自行去查资料哈。
- 数据监听
到这里全单元格的编辑已经做出来了,但是如何获取数据呢?
在输入数据时,当鼠标移开数据就消失了,这是由于在vue中数据使响应式的,这里的输入并未改变实际的状态。在Table中提供了change
API帮助获取变化,如下:
<template #bodyCell="{ record, column }" > <template v-if="['basic', 'senior', 'expert', 'trainee'].includes(column.dataIndex)" > <a-input v-if="isShowGlobalEdit" :placeholder="record[column.dataIndex]" @change="(e) => handleTableChange(e)" /> </template> </template>
复制
handleTableChange(e) { console.log(e) },
复制
可以看到每次输入都会触发事件,控制台打印一个对象,这个对象肯定式包含输入值的,找出它即可,如下:
再次改造函数如下:
<template #bodyCell="{ record, column }" > <template v-if="['basic', 'senior', 'expert', 'trainee'].includes(column.dataIndex)" > <a-input v-if="isShowGlobalEdit" :placeholder="record[column.dataIndex]" @change="(e) => handleTableChange(e.target.value, record, column)" /> </template> </template>
复制
e.target.value, record, column
这三个参数都是需要的。record, column
用于判断是那行的数据修改了,不然全局修改不知道是修改了哪些数据。
到此修改的数据就可以被实时获取了,接下来是组装数据,全局修改需要知道修改是那行的数据。
- 组装数据
一行的数据也传递到函数,如下:
由这些数据可以知道是那一行和那一列的数据,就可以组装了。
handleTableChange(e, record, column) { record[column.dataIndex] = e this.dataDuplication.push(record) },
复制
这样组装发信每次输入都会触发,导出数组重复数据,这里需要判断,由于id
是唯一的,可以根据id判断。如下:
handleTableChange(e, record, column) { // 过滤重复id this.dataDuplication = this.dataDuplication.filter((item) => item.id !== record.id) record[column.dataIndex] = e this.dataDuplication.push(record) },
复制
最终获取的数据是更改后具有id的数据,这样的数据传递到后端可以直接更具id修改。到此全部单元格修改已经完成了。