1. 官方实现方案
设置编辑按钮,点击后对应行进入可编辑状态。
参考:
https://1x.antdv.com/components/table-cn/#components-table-demo-editable-cells
2. 鼠标悬浮
悬浮在可编辑单元格上,单元格自动变为input输入框,改变内容内后,input失焦,在相应的操作区域进行保存或撤销操作。
index.vue-测试入口文件
<template>
<div class="wrapper">
<a-table :columns="columns" :data-source="tableData">
<template slot="userName" slot-scope="text, record, index">
<custom-editable-cell
:ref="getRefName('userName', index)"
:text="text"
:record="record"
@valid="onValid"
@blur="onUserNameChange(index, $event)"
/>
</template>
<template slot="action" slot-scope="text, record, index">
<a-button v-show="record.showOp" type="primary" @click.stop="colSaveClick(record)">保存</a-button>
<a-button v-show="record.showOp" @click.stop="colCancelSaveClick(index, record)">取消</a-button>
<a-icon
v-show="!record.showOp"
type="eye"
title="查看详情"
@click.stop="checkDetailClick(record)"
/>
</template>
</a-table>
</div>
</template>
<script>
import customEditableCell from './customEditableCell';
import { cloneDeep, isEqual } from 'lodash';
const columns = [
{
title: '用户名',
dataIndex: 'userName',
key: 'userName',
scopedSlots: { customRender: 'userName' },
ellipsis: true,
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
width: 160,
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
width: '30%',
},
{
title: '操作',
key: 'action',
scopedSlots: { customRender: 'action' },
width: 200,
align: 'center'
}
];
const userNameExp = /^[a-zA-Z0-9_]+$/;
export default {
name: '',
components: { customEditableCell },
data() {
return {
columns,
tableData: [],
tableDataOriginal: [], //初始数据,控制每行保存和取消显隐
isValid: true // 校验状态
};
},
mounted() {
this.getData();
},
methods: {
// 表格数据获取
getData() {
this.tableData = [
{
key: '1',
userName: 'John',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
userName: 'Jim',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
userName: 'Joe',
age: 32,
address: 'Sidney No. 1 Lake Park',
}
];
// 缓存原始数据
this.tableDataOriginal = cloneDeep(this.tableData);
},
getRefName(colName, index) {
return `${colName}_${index}`;
},
onValid(columnData) {
this.$message.destroy();
let value = userNameExp.test(columnData);
if (!value) {
this.isValid = false;
this.$message.error('用户名校验失败');
return false;
}
this.isValid = true;
},
// 监听userName修改
onUserNameChange(index, val) {
this.tableData.splice(
index,
1,
{
...this.tableData[index],
userName: val.value
}
);
this.toogleSaveBtnStatus(index);
},
// 改变行信息保存按钮显隐状态
toogleSaveBtnStatus(index) {
delete this.tableDataOriginal[index].showOp;
delete this.tableData[index].showOp;
this.tableData.splice(
index,
1,
{
...this.tableData[index],
showOp: !isEqual(this.tableData[index], this.tableDataOriginal[index])
}
);
},
// 行信息保存按钮点击事件监听
colSaveClick(newRecord) {
if (this.isValid) {
// 校验通过
console.log('调用接口更新数据', newRecord);
} else {
// 校验失败
this.onValid(newRecord);
}
},
// 行信息保存取消按钮事件监听
colCancelSaveClick(index) {
// 数据还原
this.tableData.splice(
index,
1,
{ ...this.tableDataOriginal[index] }
);
// 表格显示数据还原
if (this.$refs['userName_' + index]) {
this.$refs['userName_' + index].value = this.tableDataOriginal[index]['userName'];
}
},
// 查看用户详情点击事件监听
checkDetailClick(record) {
console.log('查看详情', record);
}
}
};
</script>
<style lang="less" scoped>
.wrapper {
overflow: hidden;
width: 100%;
height: 100%;
}
</style>
customEditableCell.vue-比较基础的自定义可编辑单元格组件
<template>
<div class="editable-cell">
<span v-show="!editable" class="text-display" :title="value">
{{ value }}
</span>
<a-input
class="opcity0"
:class="{ opcity10: editable }"
:maxLength="maxLength"
:title="value"
:value="value"
@blur="onBlur"
@change="handleChange"
@focus="isFocus = true"
@input="onInput"
@mouseenter.native="showInput(true)"
@mouseleave.native="showInput(false)"
/>
</div>
</template>
<script>
export default {
props: {
text: String,
maxLength: {
default: 999,
type: Number
}
},
data() {
return {
value: '',
editable: false,
isFocus: false
};
},
watch: {
text(nVal, oVal) {
if (nVal) {
this.value = nVal;
}
}
},
mounted() {
this.value = this.text;
},
methods: {
handleChange(e) {
let value = e.target.value;
this.value = value;
},
onBlur(e) {
this.value = e.target.value;
this.editable = false;
this.isFocus = false;
this.$emit('blur', this.value);
},
showInput(status) {
if (this.isFocus) {
return;
}
this.editable = status;
},
onInput(e) {
this.$emit('valid', this.value);
}
}
};
</script>
<style lang="less">
.editable-cell {
position: relative;
width: 100%;
.text-display {
position: absolute;
line-height: 33px;
padding-left: 12px;
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
</style>