初步实现
<template>
<a-button class="editable-add-btn" style="margin-bottom: 8px" @click="handleAdd">Add</a-button>
<a-table bordered :data-source="dataSource" :columns="columns">
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'name'">
<div class="editable-cell">
<div v-if="editableData[record.key]" class="editable-cell-input-wrapper">
<a-input v-model:value="editableData[record.key].name" @pressEnter="save(record.key)"/>
<check-outlined class="editable-cell-icon-check" @click="save(record.key)"/>
</div>
<div v-else class="editable-cell-text-wrapper">
{{ text || ' ' }}
<edit-outlined class="editable-cell-icon" @click="edit(record.key)"/>
</div>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a-popconfirm
v-if="dataSource.length"
title="Sure to delete?"
@confirm="onDelete(record.key)"
>
<a>Delete</a>
</a-popconfirm>
</template>
</template>
</a-table>
</template>
<script setup>
import {computed, reactive, ref} from 'vue';
import {CheckOutlined, EditOutlined} from "@ant-design/icons-vue";
import {cloneDeep} from 'lodash-es';
const columns = [
{
title: 'name',
dataIndex: 'name',
width: '30%',
},
{
title: 'age',
dataIndex: 'age',
},
{
title: 'address',
dataIndex: 'address',
},
{
title: 'operation',
dataIndex: 'operation',
},
];
const dataSource = ref([
{
key: '0',
name: 'Edward King 0',
age: 32,
address: 'London, Park Lane no. 0',
},
{
key: '1',
name: 'Edward King 1',
age: 32,
address: 'London, Park Lane no. 1',
},
]);
const count = computed(() => dataSource.value.length + 1);
const editableData = reactive({});
const edit = key => {
editableData[key] = cloneDeep(dataSource.value.filter(item => key === item.key)[0]);
};
const save = key => {
Object.assign(dataSource.value.filter(item => key === item.key)[0], editableData[key]);
delete editableData[key];
};
const onDelete = key => {
dataSource.value = dataSource.value.filter(item => item.key !== key);
};
const handleAdd = () => {
const newData = {
key: `${count.value}`,
name: `Edward King ${count.value}`,
age: 32,
address: `London, Park Lane no. ${count.value}`,
};
dataSource.value.push(newData);
};
</script>
<style lang="less" scoped>
.editable-cell {
position: relative;
.editable-cell-input-wrapper,
.editable-cell-text-wrapper {
padding-right: 24px;
}
.editable-cell-text-wrapper {
padding: 5px 24px 5px 5px;
}
.editable-cell-icon,
.editable-cell-icon-check {
position: absolute;
right: 0;
width: 20px;
cursor: pointer;
}
.editable-cell-icon {
margin-top: 4px;
display: none;
}
.editable-cell-icon-check {
line-height: 28px;
}
.editable-cell-icon:hover,
.editable-cell-icon-check:hover {
color: #108ee9;
}
.editable-add-btn {
margin-bottom: 8px;
}
}
.editable-cell:hover .editable-cell-icon {
display: inline-block;
}
</style>
渲染后端接口数据
<script setup>
import {computed, onMounted, reactive, ref} from 'vue';
import {CheckOutlined, EditOutlined} from "@ant-design/icons-vue";
import {cloneDeep} from 'lodash-es';
import axios from "axios";
const columns = [
{
name: '姓名',
dataIndex: 'name',
key: 'name',
},
{
name: '性别',
dataIndex: 'gender',
key: 'gender',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '电话',
dataIndex: 'phone',
key: 'phone',
},
{
title: '邮箱',
key: 'email',
dataIndex: 'email',
},
{
title: '薪资',
key: 'salary',
dataIndex: 'salary',
},
{
title: '操作',
key: 'action',
},
];
const dataSource = ref([]);
onMounted(() => {
axios.get("http://127.0.0.1:8889/zdppy_amuserdetail").then((response) => {
console.log("response.data", response.data);
dataSource.value = response.data.data.results;
})
})
const count = computed(() => dataSource.value.length + 1);
const editableData = reactive({});
const edit = id => {
console.log("edit", editableData, id)
editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
};
const save = id => {
Object.assign(dataSource.value.filter(item => id === item.id)[0], editableData[id]);
delete editableData[id];
};
const handleAdd = () => {
const newData = {
key: `${count.value}`,
name: `Edward King ${count.value}`,
age: 32,
address: `London, Park Lane no. ${count.value}`,
};
dataSource.value.push(newData);
};
</script>
<template>
<a-button class="editable-add-btn" style="margin-bottom: 8px" @click="handleAdd">Add</a-button>
<a-table
bordered
:data-source="dataSource"
:columns="columns"
:row-key="record => record.id"
>
<template #headerCell="{ column }">
<template v-if="column.key === 'name'">
<span>
{{ column.name }}
</span>
</template>
<template v-else-if="column.key === 'gender'">
<span>
{{ column.name }}
</span>
</template>
</template>
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'name'">
<div class="editable-cell">
<div v-if="editableData[record.id]" class="editable-cell-input-wrapper">
<a-input v-model:value="editableData[record.id].name" @pressEnter="save(record.id)"/>
<check-outlined class="editable-cell-icon-check" @click="save(record.id)"/>
</div>
<div v-else class="editable-cell-text-wrapper">
{{ text || ' ' }}
<edit-outlined class="editable-cell-icon" @click="edit(record.id)"/>
</div>
</div>
</template>
<template v-else-if="column.key === 'action'">
<a-space wrap>
<a-button size="small" type="primary" block>编辑</a-button>
<a-button size="small" block>详情</a-button>
<a-button size="small" danger block>删除</a-button>
</a-space>
</template>
</template>
</a-table>
</template>
<style lang="less" scoped>
.editable-cell {
position: relative;
.editable-cell-input-wrapper,
.editable-cell-text-wrapper {
padding-right: 24px;
}
.editable-cell-text-wrapper {
padding: 5px 24px 5px 5px;
}
.editable-cell-icon,
.editable-cell-icon-check {
position: absolute;
right: 0;
width: 20px;
cursor: pointer;
}
.editable-cell-icon {
margin-top: 4px;
display: none;
}
.editable-cell-icon-check {
line-height: 28px;
}
.editable-cell-icon:hover,
.editable-cell-icon-check:hover {
color: #108ee9;
}
.editable-add-btn {
margin-bottom: 8px;
}
}
.editable-cell:hover .editable-cell-icon {
display: inline-block;
}
</style>
将修改的数据保存到数据库
<script setup>
import {computed, onMounted, reactive, ref} from 'vue';
import {CheckOutlined, EditOutlined} from "@ant-design/icons-vue";
import {cloneDeep} from 'lodash-es';
import axios from "axios";
const columns = [
{
name: '姓名',
dataIndex: 'name',
key: 'name',
},
{
name: '性别',
dataIndex: 'gender',
key: 'gender',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '电话',
dataIndex: 'phone',
key: 'phone',
},
{
title: '邮箱',
key: 'email',
dataIndex: 'email',
},
{
title: '薪资',
key: 'salary',
dataIndex: 'salary',
},
{
title: '操作',
key: 'action',
},
];
const dataSource