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>
相关推荐
好看资源平台4 分钟前
前端框架对比与选择:如何在现代Web开发中做出最佳决策
前端·前端框架
4triumph7 分钟前
Vue.js教程笔记
前端·vue.js
程序员大金23 分钟前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis
清灵xmf27 分钟前
提前解锁 Vue 3.5 的新特性
前端·javascript·vue.js·vue3.5
程序员大金33 分钟前
基于SpringBoot的旅游管理系统
java·vue.js·spring boot·后端·mysql·spring·旅游
白云~️40 分钟前
监听html元素是否被删除,删除之后重新生成被删除的元素
前端·javascript·html
金灰1 小时前
有关JS下隐藏的敏感信息
前端·网络·安全
Yxmeimei1 小时前
css实现居中的方法
前端·css·html
6230_1 小时前
git使用“保姆级”教程2——初始化及工作机制解释
开发语言·前端·笔记·git·html·学习方法·改行学it
二川bro1 小时前
Vue 修饰符 | 指令 区别
前端·vue.js