Vue3中el-table组件实现分页,多选以及回显

el-table组件实现分页,多选以及回显

需求

  1. 使用 dialog 显示 table,同时关闭时销毁
  2. el-table 表格多选
  3. 回显已选择的表格数据,分页来回切换依然正确显示数据
  4. 点击取消,数据回到初始化勾选状态

思路

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>
相关推荐
William_Xu7 小时前
React 新旧生命周期对比
前端
PBitW8 小时前
为什么vite中TS报错,可以继续运行?Webpack不行?💡
前端·typescript
GISer_Jing8 小时前
一套H5跑通三端:App+小程序内嵌H5跨端适配全栈解决方案
前端·前端框架·ai编程
码云之上8 小时前
项目团队从 5 人扩到 15 人,我写了个 CLI 让 IDE 共享 AI 规则
前端·人工智能·后端
飞天狗8 小时前
LCP / INP / CLS 三个维度的实战调优:把 Web Vitals 从不及格拉到优秀的完整路径
前端·性能优化
Csvn8 小时前
Vue 3 `<script setup>` 解构 props 后响应式丢了?一个「字段不更新」的排查实录
前端
用户298698530148 小时前
前端 Excel 处理进阶:React 中合并与取消合并单元格的实现
前端·javascript·react.js
Highcharts8 小时前
@highcharts/react完整技术指南|新版Highcharts React使用、迁移、SSR、TS 优化全解
前端·javascript
老王以为9 小时前
Fiber 节点 —— 一个数据结构如何承载整个 React 运行时
前端·react native·react.js