vue3 + Element Plus实现可翻页CRUD表格
整体
<template>
<div class="project_main">
<div class="alert_box">
<el-alert v-if="alert.show" :title="alert.title" :type="alert.type" closable @close="handleAlertClose" />
</div>
<el-dialog v-model="confirmdialog" title="Warning" width="30%" center>
<span>Confirm deleting this data row
</span>
<template #footer>
<span class="dialog-footer">
<el-button @click="confirmdialog = false">Cancel</el-button>
<el-button type="primary" @click="confirmDelete">
Confirm
</el-button>
</span>
</template>
</el-dialog>
<div class="search_box">
<el-form :inline="true" class="search_info">
<el-form-item label="project:">
<el-input v-model="projectname" placeholder="项目名" clearable />
</el-form-item>
<el-form-item label="owner:" >
<el-input v-model="projectowner" placeholder="负责人" clearable />
</el-form-item>
<el-form-item label="rank:">
<el-select
v-model="projectrank"
class="m-2"
placeholder="Select"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit(1,10,projectname,projectowner,projectrank)">Query</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" class="add_row" @click="handleAdd">Add</el-button>
</el-form-item>
</el-form>
</div>
<div class="project_table_box">
<el-table :data="projectlist" style="width: 100%" :row-height="rowHeight">
<el-table-column fixed prop="project_name" label="项目名" width="150">
<template #default="{ row }">
<span v-if="!row.editing && !row.addediting">{{ row.project_name }}</span>
<el-input
v-else
v-model="row.editName"
></el-input>
</template>
</el-table-column>
<el-table-column prop="project_rank" label="重要等级" width="140" >
<template #default="{ row }">
<span v-if="!row.editing && !row.addediting">{{ row.project_rank }}</span>
<el-select
v-else
v-model="row.editRank"
class="m-2"
placeholder="Select"
size="large"
style="width: 110px"
clearable
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="project_owner_id" label="负责人" width="120">
<template #default="{ row }">
<span v-if="!row.editing && !row.addediting">{{ row.project_owner_id }}</span>
<el-input
v-else
v-model="row.editOwner"
></el-input>
</template>
</el-table-column>
<el-table-column prop="project_create_time" label="创建时间" width="320" />
<el-table-column prop="project_last_mod" label="最后修改时间" width="600" />
<el-table-column fixed="right" label="Operations" width="240">
<template #default="{ row, $index }" class="operation_box">
<el-button size="small" v-if="!row.editing && !row.addediting" @click="handleEdit(row, $index)">Edit</el-button>
<el-button size="small" type="danger" v-if="row.editing && !row.addediting" @click="handleConfirm(row, $index)">Confirm</el-button>
<el-button size="small" type="danger" v-if="!row.editing && !row.addediting" @click="handleDelete(row, $index)">Delete</el-button>
<el-button size="small" v-if="row.editing" @click="handleCancel(row, $index)">Cancel</el-button>
<el-button size="small" type="danger" v-if="row.addediting" @click="handleaddConfirm(row, $index)">Confirm2</el-button>
<el-button size="small" v-if="row.addediting" @click="handleaddCancel(row, $index)">Cancel2</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination">
<div class="demo-pagination-block">
<div class="demonstration">每页显示数</div>
<el-pagination
v-model:current-page="page"
v-model:page-size="page_size"
:page-sizes="[10, 20, 30, 40, 50]"
:small="small"
:disabled="disabled"
:background="background"
layout="sizes, prev, pager, next"
:total="total_items"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { projectrequest, projectupdate, projectdelete } from '../network/projectrequest';
const projectlist = ref([]);
const page = ref(1);
const page_size = ref(10);
const rowHeight = 40;
const small = ref(false);
const background = ref(false);
const disabled = ref(false);
const projectname = ref('');
const projectowner = ref('');
const pagination_ctl = ref();
const total_items = ref();
const projectrank = ref('');
const confirmdialog = ref(false);
const options = [
{
value: 'P0',
label: 'P0',
},
{
value: 'P1',
label: 'P1',
},
{
value: 'P2',
label: 'P2',
},
{
value: 'P3',
label: 'P3',
},
{
value: 'P4',
label: 'P4',
},
{
value: 'P5',
label: 'P5',
},
];
const alert = ref({
show: false,
type: 'success',
title: 'Success alert',
});
function handleAlertClose() {
alert.value.show = false;
}
onMounted(() => {
projectinfo(page.value, page_size.value)
});
function projectinfo(currentpage,currentpage_size,projectname,projectowner,projectrank){
projectrequest(currentpage, currentpage_size,projectname,projectowner,projectrank).then((res) => {
console.log(res.data)
console.log(res)
projectlist.value = res.data.data;
pagination_ctl.value = res.data.pagination;
total_items.value = pagination_ctl.value['total_items'];
});
}
function handleSizeChange(pagesize_now){
page_size.value = pagesize_now;
page.value = 1;
projectinfo(page.value, page_size.value, projectname.value, projectowner.value, projectrank.value);
}
function handleCurrentChange(page_now){
page.value = page_now
projectinfo(page.value, page_size.value, projectname.value, projectowner.value, projectrank.value);
}
function handleSubmit(currentpage,currentpage_size,projectname,projectowner,projectrank) {
projectinfo(currentpage,currentpage_size,projectname,projectowner,projectrank);
projectname = '';
projectowner = '';
}
function handleEdit(row, index) {
projectlist.value[index].editName = row.project_name;
projectlist.value[index].editOwner = row.project_owner_id;
projectlist.value[index].editRank = row.project_rank;
projectlist.value[index].editing = true;
}
function handleConfirm(row, index) {
const editedData = {
project_id: row.project_id,
project_name: row.editName,
project_rank: row.editRank,
project_owner_id: row.editOwner,
};
// console.log(editedData);
projectupdate(editedData)
.then((res) => {
if (res.data.responsecode === 1000) {
alert.value.type = 'success';
alert.value.title = '更新成功';
alert.value.show = true;
// console.log(alert.value)
projectlist.value[index].project_name = row.editName;
projectlist.value[index].project_owner_id = row.editOwner;
projectlist.value[index].editing = false;
} else {
alert.value.type = 'error';
alert.value.title = `更新失败: ${res.data.errorMessage}`;
alert.value.show = true;
console.error('更新失败:', res.data.errorMessage);
}
})
.catch((error) => {
alert.value.type = 'error';
alert.value.title = '更新失败';
alert.value.show = true;
console.error('更新失败:', error);
});
}
function handleCancel(row, index) {
projectlist.value[index].editing = false;
}
function handleDelete(row, index){
confirmdialog.index = row.project_id;
confirmdialog.value = true;
}
function confirmDelete(){
// console.log(confirmdialog.index);
projectdelete(confirmdialog.index)
.then((response) => {
if (response.data.responsecode === 1000) {
projectlist.value.splice(confirmdialog.index, 1);
confirmdialog.value = false;
alert.value.type = 'success';
alert.value.title = '删除成功';
alert.value.show = true;
} else {
alert.value.type = 'error';
alert.value.title = `删除失败: ${response.data.data}`;
alert.value.show = true;
confirmdialog.value = false;
}
})
.catch((error) => {
alert.value.type = 'error';
alert.value.title = `删除失败: ${error}`;
alert.value.show = true;
confirmdialog.value = false;
});
}
function handleAdd() {
projectlist.value.unshift({
project_name: '',
project_rank: '',
project_owner_id: '',
project_create_time: '',
project_last_mod: '',
addediting: true,
});
}
function handleaddConfirm(row, index) {
const newData = {
project_name: row.editName,
project_rank: row.editRank,
project_owner_id: row.editOwner,
};
projectupdate(newData)
.then((res) => {
if (res.data.responsecode === 1000) {
alert.value.type = 'success';
alert.value.title = '添加成功';
alert.value.show = true;
projectinfo(page.value, page_size.value);
} else {
alert.value.type = 'error';
alert.value.title = `添加失败: ${res.data.errorMessage}`;
alert.value.show = true;
projectlist.value.splice(index, 1);
}
})
.catch((error) => {
alert.value.type = 'error';
alert.value.title = `添加失败: ${error}`;
alert.value.show = true;
projectlist.value.splice(index, 1);
});
}
function handleaddCancel(row, index) {
projectlist.value.splice(index, 1);
}
</script>
<style scoped>
.el-alert {
margin: 20px 0 0;
z-index: 1000;
}
.el-alert:first-child {
margin: 0;
}
.operation_box {
position: relative;
}
.operation_box .el-button {
position: absolute;
margin-top: 10px;
}
.operation_box .el-button:nth-child(2) {
left: 70px;
}
</style>
拆解
查询功能用表单实现,search_box部分,本质上就是用表单获取新参数,然后handleSubmit里面提交给后端,翻页也是类似的原理,获取参数-->传给后端
element本身表格不带增删改功能,主要难点在实现这块
CUD部分实现主要分两块内容:
1.表格切换可输入文本框:
需要从展示数据切换到可输入的文本框的功能有增和改,这块思路是给行(row)加一个状态属性,通过这个状态属性来切换前端展示的组件,具体看project_table_box这块
如下例,如果满足v-if="!row.editing && !row.addediting",那么这里就展示数据,如果不满足,那就变成input
<el-table-column fixed prop="project_name" label="项目名" width="150">
<template #default="{ row }">
<span v-if="!row.editing && !row.addediting">{{ row.project_name }}</span>
<el-input
v-else
v-model="row.editName"
></el-input>
</template>
</el-table-column>
控制状态切换的按钮放在了operation_box里面,增加功能的按钮为了美观放在了search_box部分
组件响应顺序:点击功能按钮--功能按钮响应函数修改前端--点击confirm--提交数据给后端,根据返回结果来改变前端/点击cancel--只改变前端,不提交数据
2.从当前行获取数据
主要利用了vue3的slot机制,也就是代码里看到的<template #default="{ row, $index }">
这玩意,这种子template的作用就是从父template那边获取元素进行渲染,default定义了获取到的这些东西的变量名,在这里,row是当前行的数据,index表示当前行的索引(也就是projectlist这个数组里的索引),operation_box因为是project_table_box里面的子表,所以他的row和project_table_box的row是一样的。我们可以通过编辑row里面的属性来实现功能,或者通过index直接访问projectlist里面对应的数据。
需要注意的是,增加功能为了给用户提供一行可以用来编辑的空表,用projectlist.value.unshift直接在数组的最前面插入了一行空数据,这种插入是前端性质的,不涉及后端交互,又因为是插入在第一位,所以插入完成或者取消后,可以使用projectlist.value.splice(index, 1)从前端删除这条数据,index表示要移除的索引,1代表要移除1条数据
删除功能和增改实现思路差不多,不过把编辑换成了一个弹窗确认,依旧是operation按钮用于切换前端,在弹出来的弹窗上面的按钮才是真正绑定交互函数的按钮