iview的表格实现单元格行编辑功能
截图:

实现功能:
实现方式
使用插槽
<template>
<layout :footerHeight="0">
<template #Opration>
<div
style="
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
"
>
<Button size="small" @click="cancelBatchEdit()" style="margin: 0 5px" v-if="age_is_edit"
>取消批量编辑</Button
>
<Button type="primary" size="small" @click="batchEdit()" style="margin: 0 5px" v-else
>批量编辑</Button
>
<Button type="primary" size="small" @click="batchSave()" style="margin: 0 5px"
>批量保存</Button
>
</div>
</template>
<template #main>
<div
style="
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
"
>
<div style="height: 92%; overflow: auto">
<Table
:data="results"
style="display: flex;height: 100%;"
:columns="[
{
title: '序号',
name: '序号',
key: 'index',
width: 90,
},
{
title: '年龄',
name: '年龄',
key: 'age',
isShow: 1,
width: 200,
resizable: 1,
sortable: 1,
slot: 'edit',
},
{
title: '备注',
name: '备注',
key: 'remark',
isShow: 1,
width: 200,
resizable: 1,
sortable: 1,
},
]"
>
<template #edit="{ row, column }">
<div
:class="column.key"
style="
cursor: pointer;
min-width: 120px;
min-height: 48px;
display: flex;
align-items: center;
"
>
<template v-if="age_is_edit">
<YsInput
@keyup.native="handleKeyup($event, row, column.key)"
v-model="row[column.key]"
@on-blur="changeValue(row, column, row[column.key], row._index)"
/>
</template>
<template v-else>
<span>{{ row[column.key] }}</span>
</template>
</div>
</template>
</Table>
</div>
<div
style="
width: 100%;
height: 8%;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<span>共 {{ page.total }} 条</span>
<Page
:current.sync="args.page_para.page_index"
:total="page.total"
:page-size-opts="pageSizeOpts"
show-sizer
@on-page-size-change="handlePageSizeChange"
@on-change="handlePageChange"
/>
</div>
</div>
</template>
</layout>
</template>
<script>
import { differenceWith, isEqual, cloneDeep } from "lodash";
export default {
data() {
return {
age_is_edit: false,
pageSizeOpts: [10, 20, 30, 40],
args: {
conditions: {
},
page_para: {
page_index: 1,
page_size: 10,
},
},
page: {
total: 0,
currnt: 1,
pageSize: 10,
},
results: [],
originalResults: [],
editResults: [],
};
},
created() {
this.getData();
},
methods: {
cancelBatchEdit() {
this.age_is_edit = false;
this.args.page_para.page_index = 1;
this.getData(1);
},
batchEdit() {
this.age_is_edit = true;
},
async batchSave() {
let data = differenceWith(this.editResults, this.originalResults, isEqual);
data = cloneDeep(data);
let reg = /^[0-9]*[1-9][0-9]*$/;
this.batchSaveService.args.t_list = [];
if (data?.length) {
for (let i in data) {
if (data[i].age && !reg.test(data[i].age)) {
this.$Message.warning(`第${data[i].index}行的年龄请输入数字!`);
return false;
}
}
this.age_is_edit = false;
await this.$http(data);
this.$Nessage.success("操作成功!");
this.args.page_para.page_index = 1;
this.getData(1);
} else {
this.$Message.info("无操作数据!");
}
},
handleKeyup(event, row, key) {
// ↑
if (event.keyCode === 38) {
if (row._index > 0) {
this.changeCurrentRow(row, key, "-");
}
}
// ↓
if (event.keyCode === 40) {
if (row._index + 2 <= this.page.pageSize) {
this.changeCurrentRow(row, key, "+");
}
}
},
changeCurrentRow(row, key, type) {
let curIndex = row._index;
if (type === "+") {
curIndex = row._index + 1;
} else {
curIndex = row._index - 1;
}
this.$set(this.results, row._index, row);
let changeRow = this.results[curIndex];
this.$set(this.results, curIndex, changeRow);
this.$nextTick(() => {
let e = document.querySelectorAll(`.${key}`)[curIndex];
e.querySelector('input').focus();
});
},
async getData(flag = 0) {
if (flag === 1) {
this.editResults = [];
this.originalResults = [];
}
let res = await this.$http({});
this.page.total = res.total;
let [pageIndex, pageSize] = [this.args.page_para.page_index, this.args.page_para.page_size];
if (res.total > 0) {
res.result.forEach((item, index) => {
// 序号
this.$set(item, "index", ((pageIndex - 1) * pageSize) + index + 1);
this.$set(item, "age_is_edit", false);
});
}
if (this.editResults.length < pageIndex * pageSize) {
// 当前表格显示数据
this.results = res.result;
// 编辑数据
this.editResults.push(...res.result);
// 原始数据
this.originalResults.push(...cloneDeep(res.result));
} else {
this.results = this.editResults.slice((pageIndex - 1) * pageSize, pageIndex * pageSize);
}
},
changeValue(row, column, val, index) {
if (val) {
if (!/^[0-9]*[1-9][0-9]*$/.test(val)) {
this.$Message.warning("请输入数字!");
this.results[index][column.key] = val;
} else {
this.results[index][column.key] = parseFloat(val);
}
}
},
},
};
</script>
使用render函数
<template>
<layout>
<template #main>
<div
style="
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
"
>
<div style="height: 92%; overflow: auto">
<Table
:data="results"
style="display: flex;height: 100%;"
:columns="[
{
title: '序号',
name: '序号',
key: 'index',
width: 90,
},
{
title: '年龄',
name: '年龄',
key: 'age',
isShow: 1,
width: 200,
resizable: 1,
sortable: 1,
render: render,
},
{
title: '备注',
name: '备注',
key: 'remark',
isShow: 1,
width: 200,
resizable: 1,
sortable: 1,
},
]"
>
</Table>
</div>
<div
style="
width: 100%;
height: 8%;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<span>共 {{ page.total }} 条</span>
<Page
:current.sync="args.page_para.page_index"
:total="page.total"
:page-size-opts="pageSizeOpts"
show-sizer
@on-page-size-change="handlePageSizeChange"
@on-change="handlePageChange"
/>
</div>
</div>
</template>
</layout>
</template>
<script>
export default {
data() {
return {
age_is_edit: false,
pageSizeOpts: [10, 20, 30, 40],
args: {
conditions: {
},
page_para: {
page_index: 1,
page_size: 10,
},
},
page: {
total: 0,
currnt: 1,
pageSize: 10,
},
results: [],
};
},
created() {
this.getData();
},
methods: {
render(h, { row, column, index }) {
return (
<div
style="cursor: pointer"
vOn:click={(e) => {
this.changeIndex(e, index, row)
}}>
{!row.nameIsEdit ? (
<span>{row[column.key]}</span>
) : (
<Input vModel={row[column.key]} vOn:on-blur={() => this.changeValue(row, column, row[column.key], index)} />
)}
</div>
)
},
async getData(flag = 0) {
let res = await this.$http({});
if (res.total > 0) {
res.result.forEach((item) => {
this.$set(item, 'nameIsEdit', false);
});
}
this.results = res.result;
},
changeValue(row, column, val, index) {
this.$set(row, 'nameIsEdit', false);
results[index][column.key] = val
},
changeIndex(e, index, row) {
this.flag = false;
this.$set(row, 'nameIsEdit', true);
//实现点击后输入框自动聚焦
this.$nextTick(() => {
e.currentTarget.getElementsByTagName("input")[0].focus();
});
},
},
};
</script>