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>
相关推荐
好名字08217 分钟前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
隐形喷火龙18 分钟前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_7482411231 分钟前
Selenium之Web元素定位
前端·selenium·测试工具
风无雨37 分钟前
react杂乱笔记(一)
前端·笔记·react.js
鑫~阳1 小时前
快速建站(网站如何在自己的电脑里跑起来) 详细步骤 一
前端·内容管理系统cms
egekm_sefg1 小时前
webrtc学习----前端推流拉流,局域网socket版,一对多
前端·学习·webrtc
m0_748234341 小时前
前端工作中问题点拆分
前端
艾斯特_1 小时前
JavaScript甘特图 dhtmlx-gantt
前端·javascript·甘特图
北海天空1 小时前
reactHooks到底钩到了什么?
前端·react.js
飞翔的渴望1 小时前
react18与react17有哪些区别
前端·javascript·react.js