el-table组件实现分页,多选以及回显
需求
- 使用 dialog 显示 table,同时关闭时销毁
- el-table 表格多选
- 回显已选择的表格数据,分页来回切换依然正确显示数据
- 点击取消,数据回到初始化勾选状态
思路
1、实现分页多选并保存上一页的选择
分别添加以下属性
Table 属性
Table-column 属性
html
<el-table ref="tableRef" row-key="id" @selection-change="handlechange">
<el-table-column type="selection" :reserve-selection="true" align="center" />
</el-table>
2、记录当前选择的数据
定义 el-table 的 selection-change 事件回调函数
typescript
const handlechange = (val: any[]) => {
selected.value = val
}
前两步已经能满足不需要回显的分页多选功能,但是要实现数据的回显还需要以下处理。
3、默认数据的回显
假设定义两个响应式数组表示默认选择和当前选择
typescript
// 默认选中列表
const defaultSelected = ref<any[]>([])
// 当前选中的列表
const selected = ref<any[]>([])
// 通过 selection-change 事件回调保存当前选择的数据
const handlechange = (val: any[]) => {
selected.value = val
}
在显示弹窗方法里通过 el-table 中的 toggleRowSelection 方法初始化选中所有默认选项(注意是所有的选项,而不只是当前页的选项),如果只选择当前页的默认选项,selected 将会丢失其他默认选项
typescript
// 显示表格弹窗
const showDialog = () => {
getTableList()
setTimeout(() => {
for (const item of defaultSelected.value) tableRef.value.toggleRowSelection(item, true) // 选中默认选中的行
}, 0)
visible.value = true
}
至此实现了所有功能,总结一下原理就是 el-table 通过 row-key 来判断是否已选择,所以通过 toggleRowSelection 选择所有默认的选项,不管点击哪一页都会正确回显数据,并且定义了 handlechange 会保存新的改变
如果每次确认后不销毁 table 组件,需要调用 clearSelection 方法清空所有已选项
typescript
const handleClick = () => {
// 保存新的数据
defaultSelected.value = cloneDeep(selected.value)
selected.value.length = 0
pagination.currentPage = 1
// 清空表格已选项
tableRef.value.clearSelection()
visible.value = false
}
完整代码
记录下代码,互相学习提提意见
typescript
<script setup lang="tsx">
import { useI18n } from '@/hooks/web/useI18n'
import { getTableListApi } from '@/api/table'
import { TableData } from '@/api/table/types'
import { ref, reactive, watch } from 'vue'
import { ElTableColumn, ElTable, ElPagination, ElButton, ElDialog } from 'element-plus'
import { cloneDeep } from 'lodash-es'
const { t } = useI18n()
const columns: any[] = [
{
type: 'selection',
width: 60,
align: 'center'
},
{
field: 'title',
label: t('tableDemo.title')
},
{
field: 'author',
label: t('tableDemo.author')
},
{
field: 'display_time',
label: t('tableDemo.displayTime'),
sortable: true
},
{
field: 'importance',
label: t('tableDemo.importance')
},
{
field: 'pageviews',
label: t('tableDemo.pageviews')
}
]
const loading = ref(true)
const visible = ref(false)
const pagination = reactive({
currentPage: 1, // 当前页数
pageSize: 10, // 每页显示条数
pageSizes: [10, 20, 30, 40, 50], // 每页显示个数选择器的选项设置
total: 100 // 总条数
})
const tableDataList = ref<TableData[]>([])
const tableRef = ref<any>()
// 默认选中列表
const defaultSelected = ref<any[]>([])
// 当前选中的列表
const selected = ref<any[]>([])
const getTableList = async () => {
// 分页查询方法
const res = await getTableListApi({ ...pagination, pageIndex: pagination.currentPage })
.catch(() => {})
.finally(() => {
loading.value = false
})
if (res) {
tableDataList.value = res.data.list
}
}
const showDialog = () => {
getTableList()
setTimeout(() => {
for (const item of defaultSelected.value) tableRef.value.toggleRowSelection(item, true) // 选中默认选中的行
}, 0)
visible.value = true
}
const handlechange = (val: any) => {
selected.value = val
}
const handleClick = () => {
defaultSelected.value = cloneDeep(selected.value)
selected.value.length = 0
pagination.currentPage = 1
// 清空选项
tableRef.value.clearSelection()
visible.value = false
}
watch(() => [pagination.currentPage, pagination.pageSize], getTableList, { immediate: true })
</script>
<template>
<!-- 控制弹窗显示 -->
<ElButton type="primary" @click="showDialog">显示</ElButton>
<!-- 表格弹窗 -->
<el-dialog title="提示" v-model="visible" width="80%" destroyOnClose>
<div class="w-full h-800px flex flex-col justify-between">
<el-table
ref="tableRef"
height="760px"
:data="tableDataList"
:loading="loading"
row-key="id"
@selection-change="handlechange"
>
<el-table-column
v-for="column in columns"
:type="column.type"
:key="column.field"
:prop="column.field"
:label="column.label"
:reserveSelection="true"
/>
</el-table>
<div class="flex justify-start">
<el-button type="primary" @click="handleClick">确认</el-button>
</div>
<!-- 分页器 -->
<div class="flex justify-end">
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="pagination.pageSizes"
/>
</div>
</div>
</el-dialog>
</template>