使用Vue + Element Plus实现可多行编辑的分页表格
需求背景:
在现代前端开发中,表格作为数据展示和交互的重要组件,在各类管理系统、数据平台中有着广泛的应用。随着用户对数据操作便捷性要求的不断提高,具备灵活编辑功能的表格成为了开发中的常见需求。特别是在需求处理大量数据时,不仅要实现数据的分页展示,还要支持对数据的实时编辑,并且要保证在复杂操作场景下的数据状态管理。
本次demo是人员信息管理的场景。
在该场景下,需要一个能够展示人员基本信息(包括ID、姓名、年龄、职业、爱好等)的表格,同时要求具备强大的编辑功能。具体来说,需要在表格中实现编辑按钮,点击后能对该行的职业和爱好进行修改,其中职业通过文本框编辑,爱好通过下拉框选择。此外,考虑到数据量较大的情况,表格需要支持分页展示,每页展示5条数据为例。更为关键的是,要实现多行数据同时编辑的功能,并且在切换分页时,能将数据恢复到初始化状态,确保用户操作的一致性和数据展示的准确性,提升系统的易用性和交互体验。
代码展示:
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ElTable, ElTableColumn, ElPagination, ElButton, ElInput, ElSelect, ElOption } from 'element-plus'interface TableItem {id: numbername: stringage: numberprofession: stringhobby: stringisEditing: booleanoriginalData?: {profession: stringhobby: string}
}const hobbies = ['读书', '运动', '音乐', '旅游', '游戏']const tableData = ref<TableItem[]>([{ id: 1, name: '张三', age: 25, profession: '工程师', hobby: '读书', isEditing: false },{ id: 2, name: '李四', age: 28, profession: '设计师', hobby: '运动', isEditing: false },{ id: 3, name: '王五', age: 30, profession: '教师', hobby: '音乐', isEditing: false },{ id: 4, name: '赵六', age: 22, profession: '学生', hobby: '游戏', isEditing: false },{ id: 5, name: '钱七', age: 35, profession: '医生', hobby: '旅游', isEditing: false },{ id: 6, name: '孙八', age: 27, profession: '销售', hobby: '运动', isEditing: false },{ id: 7, name: '周九', age: 32, profession: '会计', hobby: '读书', isEditing: false },{ id: 8, name: '吴十', age: 29, profession: '律师', hobby: '音乐', isEditing: false },{ id: 9, name: '郑十一', age: 31, profession: '记者', hobby: '旅游', isEditing: false },{ id: 10, name: '王十二', age: 26, profession: '作家', hobby: '游戏', isEditing: false },
])const currentPage = ref(1)
const pageSize = ref(5)const paginatedData = computed(() => {const start = (currentPage.value - 1) * pageSize.valueconst end = start + pageSize.valuereturn tableData.value.slice(start, end)
})const handleEdit = (row: TableItem) => {row.isEditing = truerow.originalData = {profession: row.profession,hobby: row.hobby}
}const handleSave = (row: TableItem) => {row.isEditing = false;// 实际开发中,调用接口,是否使用delete row.originalData视情况而定delete row.originalData
}const handleCancel = (row: TableItem) => {
// 取消操作时,务必还原之前的数据if (row.originalData) {row.profession = row.originalData.professionrow.hobby = row.originalData.hobby}row.isEditing = false// 实际开发中,调用接口,是否使用delete row.originalData视情况而定delete row.originalData
}const handlePageChange = (page: number) => {currentPage.value = page;// Reset editing state for all rows,仅为静态数据展示使用;实际开发调用接口,无需单独处理tableData.value.forEach(row => {if (row.isEditing) {handleCancel(row)}})
}
</script><template><div class="table-container"><el-table :data="paginatedData" style="width: 100%"><el-table-column prop="id" label="ID" width="80" /><el-table-column prop="name" label="姓名" width="120" /><el-table-column prop="age" label="年龄" width="80" /><el-table-column label="职业" width="180"><template #default="{ row }"><el-inputv-if="row.isEditing"v-model="row.profession"size="small"/><span v-else>{{ row.profession }}</span></template></el-table-column><el-table-column label="爱好" width="180"><template #default="{ row }"><el-selectv-if="row.isEditing"v-model="row.hobby"size="small"style="width: 100%"><el-optionv-for="hobby in hobbies":key="hobby":label="hobby":value="hobby"/></el-select><span v-else>{{ row.hobby }}</span></template></el-table-column><el-table-column label="操作" width="180"><template #default="{ row }"><template v-if="row.isEditing"><el-button type="success" size="small" @click="handleSave(row)">保存</el-button><el-button type="info" size="small" @click="handleCancel(row)">取消</el-button></template><el-button v-else type="primary" size="small" @click="handleEdit(row)">编辑</el-button></template></el-table-column></el-table><div class="pagination"><el-paginationv-model:current-page="currentPage":page-size="pageSize":total="tableData.length"layout="prev, pager, next"@current-change="handlePageChange"/></div></div>
</template><style scoped>
.table-container {width: 100%;max-width: 1000px;margin: 0 auto;
}.pagination {margin-top: 20px;display: flex;justify-content: center;
}.el-button {margin-right: 8px;
}.el-button:last-child {margin-right: 0;
}
</style>
上面代码仅为静态数据参考,在实际开发中,我实际的开发逻辑为下面的 条
- 初始化调用列表数据,通过map方法为每一条数据增加一个isEdit属性,值为false;增加一个originalData记录需要变更的字段或者如上所示,在interface中声明一个originalData可选属性,在编辑数据时,再进行复制
- 点击编辑,将isEdit值改为true
- 保存操作,给接口传参,将修改的值进行本地赋值,如爱好下拉框选项卡,实际开发中显示的都是Desc字段,需要进行处理。保存后,不调用列表接口,否则,就无法实现多行编辑
- 取消操作,一定要把原始值进行赋值,否则点击编辑时,显示的数据为编辑后未保存的值。
- 分页切换,展示为初始化状态,只需要正常调用接口即可。
实现效果如下图所示:
希望上述内容对你实现类似功能有所帮助。如果你有更优的实现方法或遇到了其他问题,欢迎在评论区留言分享,我们可以一起探讨优化方案。