element-plus中el-table分页勾选记住勾选内容并限制数量

文章介绍了如何在升级到Vue3和Element-Plus的项目中处理列表分页时保持跨页选择的状态,包括使用row-key、reserve-selection以及自定义方法来管理选中项,同时实现数量限制和全选/取消全选功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求背景,定制需求,列表分页+数量限制提交

前提条件:由于历史项目升级到vue3+element-plus ,故此写法还是偏于vue2的声明写法,没有用到组合式

有过研究的小伙伴们,肯定发现了,element 和element-plus中对于跨页选择保持勾选这个操作,源码进行更改,如果用element的话,用row-key + reserve-selection 即可达到切换分页时,记住之前分页的数据内容,但是element-plus可不行。

下面在线模拟一波

 然后同样的后端分页使用element,切换分页时也可以达到记忆之前勾选内容,但是element-plus按照这种方式并不能实现。

先来看一波element-plus实现的样例:

 这边我设置勾选上限25个,后端分页,切换分页记住之前选择,并达到上限之后,复选框禁用,搭配上全选功能也实现限制。

前提准备:

1.使用row-key定唯一字段、reserve-selection在type=selection勾选框栏(开启跨页记录) 使用selectable属性来控制是否可以勾选

2.尝试@select和@select-change 两个方法,发现select-change不记录跨页数据,故而采用@select,勾选单个勾选框触发的事件,可以知道当前点击行的row信息

3. @select-all 方法全选该页所有项,参数是目前选中的数据,开启跨页记录(含跨页数据)

实现思路:

1.单个选择时,判断选中的行数据是否存在选中数据数组中(currentSelection),不存在就加入存在就剔除

2.全部选择时:分两种情况 @select-all = handlerSelectAll(val)

a: val 为空 取消当前页勾选,并且其他页都没有数据   ===> 直接维护currentSelection 置空即可

b: val有数据 分两种情况

      b1: 当前页的全选

       比较当前页tableData和val差集(diff),如果tableData的数据都在val中,说明是全选,将差集添加到currentSelection即可

        b2: 其他页有数据勾选,当前页取消全选

        如果tableData的数据在val中不存在,则为取消全选,从currentSelection 剔除这些数据即可

    上述分析中再加入上限设置,全选时判断,增加差集过程中,currentSelection + diff 和 上限(maxLength) 作对比,超过限制就截断,不足就直接添加

分析完毕:下面是展示代码

<el-table
   v-show="!tableLoading && tableData.length"
   max-height="330"
   ref="multipleTable"
   :data="tableData"
   class="userCameraTable"
   row-class-name="rowClassName"
   header-row-class-name="headerRowClassName"
   border
   row-key="deviceId"
   @select="handlerSelect"
   @select-all="handlerSelectAll"
 >
   <el-table-column
     label
     width="50"
     type="selection"
     v-if="!isShowDetail"
     :selectable="handlerSelectable"
     :reserve-selection="true"
   />
  ....
handlerSelectable(row) {
  // 检查当前行是否已被选择
  const isChecked = this.currentSelection.includes(row.deviceId)
  // 如果当前行已被选择,则允许取消选择
  if (isChecked) {
     return true
  } else {
    // 如果当前行未被选择,并且已选择的行数超过max,则禁止选择新的行
     return this.currentSelection.length < this.maxLength
   }
 },
 handlerSelect(val, row) {
    this.currentSelection.indexOf(row.deviceId) === -1
      ? this.currentSelection.push(row.deviceId)
      : this.currentSelection.splice(this.currentSelection.indexOf(row.deviceId), 1)
 },
 handlerSelectAll(val) {
   if (val.length) {
     // 进来此处说明:
     // 1 当前页的全选 2 其他页有数据然后当前页的取消全选
     // 比较全选或者取消全选与当前页的数据,得到差集
     // 如果tableData中的数据在val中不存在,则说明是取消全选,需要从currentSelection中移除
     // 如果tableData中所有的数据都在val中存在,则说明是全选,需要将差集添加到currentSelection中
     const isAllSelect = this.tableData.every(item =>
     val.some(valItem => valItem.deviceId === item.deviceId)
    )
    if (isAllSelect) {
       // 全选中新增的差集
      const diff = val.filter(
      item => !this.currentSelection.some(deviceId => deviceId === item.deviceId)
     )
     if (this.currentSelection.length + diff.length > this.maxLength) {
         this.currentSelection = this.currentSelection.concat(
           diff.splice(0, this.maxLength - this.currentSelection.length)
              .map(item => item.deviceId))
         diff.forEach(item => this.$refs.multipleTable.toggleRowSelection(item, false))
     } else {
         this.currentSelection = this.currentSelection.concat(diff.map(item => item.deviceId))
     }
    } else {
        this.currentSelection = this.currentSelection.filter(
          deviceId => !this.tableData.some(item => item.deviceId === deviceId)
        )
      }
    } else {
      // 进来此处说明:
      // 其他页并无勾选数据,且当前页取消勾选
      this.currentSelection = []
    }
  },


// getTableData 
async getCameraList() {
...
const res = await this.$api.getCameraListByGroup(data)
  if (res.cameraList && res.cameraList.length) {
      this.totalNum = res.pageInfo.totalNum
      this.tableData = res.cameraList
// 需要这部分,每当切换分页获取新一页的tableData时,双循环遍历把当前tableData中有存在维护已选数据中的id手动设置勾选
      if (this.currentSelection.length) {
            this.$nextTick(() => {
              this.currentSelection.forEach(row => {
                this.tableData.forEach(item => {
                  if (item.deviceId === row) {
                    this.$refs.multipleTable?.toggleRowSelection(item, true)
                  }
                })
              })
            })
          } else {
            this.$refs.multipleTable?.clearSelection()
          }
          this.$nextTick(() => {
            this.$refs.multipleTable?.doLayout()
            this.$refs.multipleTable?.setScrollTop(0)
          })
        }
...
      } 
    }

至于打开弹框再回显数据,就让后端返参,返回所有的勾选数据,前端直接赋值ids给currentSelection即可。

### Vue3 Element Plus 复选框分页回显解决方案 在处理 `Vue3` 和 `Element Plus` 的表格组件时,为了实现在分页切换后保持已选择项的状态,可以采用以下方案: #### 数据结构设计 确保数据模型能够保存每一页的选择状态。通常做法是在页面级的数据对象中维护一个映射表来记录哪些行被选中。 ```javascript const selectedRowsMap = ref(new Map()); ``` 此变量用于存储每一行唯一标识符到其是否已被勾选的布尔值之间的对应关系[^1]。 #### 表格配置 当初始化表格或加载新页码的数据时,应遍历当前显示的数据集设置默认选中的行。这可以通过监听分页事件在每次更新视图之前同步选择状态完成。 ```html <template> <el-table :data="tableData" @selection-change="handleSelectionChange"> <!-- 列定义 --> <el-table-column type="selection" width="55"></el-table-column> ... </el-table> <div class="pagination-container"> <el-pagination layout="prev, pager, next" :total="total" @current-change="handlePageChange"/> </div> </template> ``` 每当发生分页变化时触发 `handlePageChange` 方法,在该方法内部重新计算哪几条记录应该处于选中状态,通过编程方式调用 `toggleRowSelection()` 来恢复这些选项。 ```typescript import { ElTable } from "element-plus"; // 假设 tableRef 是指向 el-table 组件实例的一个 Ref const handlePageChange = (currentPage) => { // 获取新的数据列表... const currentSelectedKeys = Array.from(selectedRowsMap.value.keys()).filter(key => newDataList.some(item => item.id === key)); nextTick(() => { currentSelectedKeys.forEach((key) => { const row = newDataList.find(item => item.id === key); if(row){ tableRef.value.toggleRowSelection(row, true); } }); }); }; ``` 上述逻辑确保即使用户翻阅不同页面再返回原位置也能看到之前的多选结果得以保留[^2]。 对于渲染函数的具体实现细节以及如何自定义单元格内容可参见提供的 E-expand.js 文件说明;而对于属性配置方面,则需要注意像 `<el-tree-select>` 这样的控件需要正确指定 `props` 属性才能正常工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值