0 前言

在前端开发过程中时常会遇到表格相关的显示与处理。组件库通常都会提供表格组件,对于展示、简单操作这些常用功能通常也够用;但如果需要更多的定制或进行比较复杂的操作,组件库自带的组件可能会捉襟见肘。vxe-table是一个基于Vue.js的功能较为完善的表格组件库,常用功能易于上手,也有很多高级功能。

最近做项目时使用了vxe-table库,期间遇到一个需求(感觉也算是比较常见的场景)

从多页表格中选择一些项,把选中的项返回给后端

然而在实现的时候发现一个问题:由于每次翻页时是重新从后端请求并更新表格展示的数据,所以一旦翻页,这一页已经选中的复选框就丢失了。

1 解决思路

最直接的办法当然是不翻页,或者在每次翻页前必须先提交;但显然只有在特定的业务场景中才能这样使用。对于通用情况,不难想到如下思路:

  • 翻页之前将复选框状态保存下来
  • 翻页之后还原新页面的复选框状态
  • 提交时将所有选中的项目提交

最终的实现方案是使用一个 Set 保存所有选中的项目id,下面详细介绍代码实现。(之前还想了一个有点奇怪的方案,没有采用,写在最后了。)

2 代码实现

vxe-table 配置

<vxe-table
ref="paperTable"
row-id="id"
@checkbox-change="togglePaperSelect"
@checkbox-all="toggleAllPaperSelect"
>
<vxe-table-column type="checkbox" width="60"></vxe-table-column>
<vxe-table-column field="title" title="标题"></vxe-table-column>
<!-- other columns -->
</vxe-table>
<vxe-pager
@page-change="handlePageChange"
>
</vxe-pager> <Button @click="submitAddPaper">确认</Button>

以上是要用到的一些主要配置(有部分省略)

  • Vue 提供的 ref 属性便于在script中访问表格,省去 getElement 等操作

  • row-id 给每行设置一个自定义的id,对应行数据中的一个属性,并且需要保证唯一。最好设置这个选项,之后保存和设置的时候更方便。如果不设置他会自动生成一个id,不过自动id每次会改变,无法作为选择和保存的依据。

  • checkbox-change checkbox-all 两个事件绑定,顾名思义就是点击每一行中的复选框/表头的全选复选框时触发的事件

保存复选框状态

由于要进行高频的添加、删除、查询操作,所以比起顺序存储的 Array ,使用哈希表的 Set 明显更加适合。Set 的三个基本操作:

let s = new Set();
s.add('a'); // 添加
s.has('a'); // 查询
s.delete('a'); // 删除

只需要在每次复选框状态发生变动时将对应的项目加入/移出 Set 即可。注意表头的全选框和每行中的复选框对应两个不同事件,不要忘记单独设置。

事件返回的 payload 中可以说是应有尽有,这里只取了两个需要用到的:行 id 和复选框的新状态(true/false)

  • 自定义设置了 row-id 配置后 rowid 属性才有意义,因为自动生成的id会改变。如果实在没有适合当id的属性,或者需要取整个对象,可以使用 payload 里的 row 字段

  • 【21.03.11 勘误】全选框这里有个坑。虽然全选中和全取消选中都是 checkbox-all 事件,但返回的 payload.records 不同:

    • 选中时返回的 records 是一个 Array<row> ,每个 row 对象就是表格中的一行数据

    • 取消选中时 records 为空列表,从事件中获取不到都取消了哪些项目

// 在data中定义:selectedPapers: new Set()

togglePaperSelect({ rowid, checked }) {
if (checked) {
this.selectedPapers.add(rowid);
} else {
this.selectedPapers.delete(rowid);
}
}, toggleAllPaperSelect({records, checked}) {
if (checked) {
records.forEach(item => this.selectedPapers.add(item.id))
} else {
// 注意取消全选时需要遍历当前表格数据来删除,records不管用
this.paperResult.forEach(item => this.selectedPapers.delete(item.id));
}
},

设置新的复选框状态

虽然 vxe-table 提供了 checkRowKeys 配置设置默认选中的行,但是只在表格第一次渲染的时候生效,因此只能手动设置选中的复选框。

不知道为什么 vxe-table 没有提供用 id 设置复选框的 api,只能传入整个 row 作为参数。所以只能先通过 id 获取到 row,再设置这一行的复选框状态为 true。

  • 翻页时先正常请求到新页中的数据,加载完新数据之后遍历检查,如果是之前保存过的项,就设置复选框为选中
  • setCheckboxRow() getRowById() 都是 table 提供的 api,所以需要先拿到表格的引用
handlePageChange({ currentPage, pageSize }) {
// request new page
this.queryPaper().then(() => {
let table = this.$refs.paperTable; this.paperResult.forEach((paper) => {
if (this.selectedPapers.has(paper.id)) {
table.setCheckboxRow(table.getRowById(paper.id), true);
}
});
});
},

完成上述设置后就可以实现翻页时保存复选框状态的需求了。

获取选中项

因为监听了所有复选框改变的事件,所以 Set 中的内容就是最终所有被选中的内容,因此只需要在提交的时候将 Set 转换为 Array 即可。

let ids = Array.from(this.selectedPapers);

到此为止就实现了需求的所有功能。

3 一个不太合理的尝试

其实最初的思路是十分简单粗暴地保存一个列表的列表,即把每一页中选取的 id 分别保存,提交时再合并。虽然最终没有采用,但在写这一版代码的过程中也学习了一些新方法,将代码贴上来记录一下。同时希望分析的过程也能提供一些参考。

这样的思路存在一些优点,比如:

  • 只有在翻页时才保存更改,翻页前反复修改复选框的操作不会带来消耗,也不需要单独考虑全选框的问题
  • 每页设置复选框的时候不需要一个一个查询,直接主动设置已经选中的,如果一页内容很多同时选中的内容很少可能存在一点点性能优势

但最终没有使用它是因为它有更多问题:

  • 逻辑问题:如果一页的大小发生改变,或查询过程中表格中的数据增加了导致页的位置发生改变,会直接失效
  • 代码质量问题:二维数组和多个状态变量都增加了代码的理解难度,也明显没有上面的方法简洁优雅
  • 由于哈希表的CRD效率都很高,对于实际中点击复选框的操作频率来说性能开销的差异很小
// 每次翻页时保存当前页中选中的项目,之后加载新页中选中的项目
handlePageChange({ currentPage, pageSize }) {
// save selected ids in current page
let table = this.$refs.paperTable;
let ids = table.getCheckboxRecords().map((item) => item.id);
this.selectedPapers[this.paperPageParam.pageNum] = ids; // request new page
this.queryPaper().then(() => {
// load saved ids in new page
let currents = this.selectedPapers[currentPage];
if (currents) {
currents.forEach((rowid) => {
table.setCheckboxRow(table.getRowById(rowid), true);
});
}
this.selectedPapers[currentPage] = [];
});
}, // 提交时合并为一个列表
getAllSelectedPapers() {
let table = this.$refs.paperTable;
let ids = table.getCheckboxRecords().map((item) => item.id);
this.selectedPapers[this.paperPageParam.pageNum] = ids; let definedLists = this.selectedPapers.filter((item) => item);
return [].concat(...definedLists);
},

结语&参考资料

以上就是我个人在项目过程中遇到的问题以及解决办法,由于个人能力所限,用到的方法可能不是最好的,也可能存在各种问题,欢迎大家讨论与指正。

参考资料:vxe-table 官方文档

前端 | vxe-table 翻页保留复选框状态的更多相关文章

  1. 关于MUI v0.18.0版本 Table组件里的复选框不能选的解决方案

    前段时间在用MUI的时候,Table组件出现复选框不能选的bug(描述: 点击复选框,点击事件会触发,复选框勾选状态无变化). 解决方法: 用CheckBox组件代替Table组件自带的复选框. 解决 ...

  2. 自动化测试-15.selenium单选框与复选框状态判断

    本篇主要介绍单选框和复选框的操作 一.认识单选框和复选框 1.先认清楚单选框和复选框长什么样 2.各位小伙伴看清楚哦,上面的单选框是圆的:下图复选框是方的,这个是业界的标准,要是开发小伙伴把图标弄错了 ...

  3. element ui中表格table翻页记忆勾选状态

    <el-table ref="multipleTable" :data="datalist" style="width:100%" @ ...

  4. web前端 ajax加载动态生成复选框demo

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. Checkbox 勾上 不让勾下 同步手动刷新复选框状态 iview

    <Checkbox v-show="!disabledForm" ref="youwubianhuaRef" :value="youwubian ...

  6. PyQt(Python+Qt)学习随笔:复选框状态枚举类Qt.CheckState取值及含义

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿Python,跟老猿学Python! 老猿Python博文目录 专栏:使用PyQt开发图形界面P ...

  7. 关于通过jq /js 实现验证单选框 复选框是否都有被选中

    今天项目中遇到一个问题 就是要实现,单选框,复选框 同时都被选中才能进行下一步的问题,开始用js原生来写 怎么写都觉得不合适,通过for循环得出 复选框被选中的,在通过for循环得出单选框被选中的,问 ...

  8. 复选框input:checkbox

      复选框 CreateTime--2017年6月5日14:04:55Author:Marydon 五.复选框 (一)语法 <input type="checkbox" /& ...

  9. element-ui 复选框,实现点击表格当前行选中或取消

    背景: 1.表格结构绑定事件 <el-table v-loading="StepsListLoading" :data="StepsListData" b ...

随机推荐

  1. 小程序 webview 自动打开新页面

    小程序 webview 自动打开新页面 iframe 效果 https://nervjs.github.io/taro/docs/components/open/web-view.html 怎么阻止小 ...

  2. React Styleguidist

    React Styleguidist https://www.thoughtworks.com/cn/radar/techniques/micro-frontends https://github.c ...

  3. 图像仿射变换——MatLab代码实现

    这里先说一下我们的目的,最近在用Pix2Pix 做一个项目的时候,遇到了成对图像质量差,存在着特征不能对齐的问题,即A图与B图是一组成对图像,我们想要将A 图中的物体转化为B 图中的物体,但这个物体在 ...

  4. 还原Oracle数据库dmp文件(Win系统)

    准备工作: 1.核对数据字符集:   一般Oracle在安装的时候默认是选择ZHS16GBK,如有改动,使用 select userenv('language') from dual;语句查看使用的字 ...

  5. sql语句的练习,已练习的会以绿色标注!!!

    表架构 Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师 ...

  6. 使用Docker快速搭建Nginx+PHP-FPM+MySQL+phpMyAdmin环境

    一.概述 环境介绍 操作系统:centos 7.6 docker版本:19.03.8 ip地址:192.168.31.34 本文将介绍如何使用单机部署Nginx+PHP-FPM环境 二.Nginx+P ...

  7. web前端学习笔记(python)(一)

    瞎JB搞]感觉自己全栈了,又要把数据库里面的内容,以web形式展示出来,并支持数据操作.占了好多坑.....慢慢填(主要参考廖雪峰的官网,不懂的再百度) 一.web概念 Client/Server模式 ...

  8. Python基础之:Python中的流程控制

    目录 简介 while语句 if 语句 for语句 Break Continue pass 简介 流程控制无非就是if else之类的控制语句,今天我们来看一下Python中的流程控制会有什么不太一样 ...

  9. 剑指 Offer 35. 复杂链表的复制

    剑指 Offer 35. 复杂链表的复制 Offer_35 题目详情 方法一 可以使用一个HashMap来存储旧结点和新结点的映射. 这种方法需要遍历链表两遍,因为需要首先知道映射关系才能求出next ...

  10. 剑指 Offer 26. 树的子结构

    剑指 Offer 26. 树的子结构 Offer 26 题目详情: 题解分析 解法一: 第一种比较容易想到的解法就是查看这两棵树的前序遍历和中序遍历序列是否都匹配. 因为前序遍历和中序遍历可以唯一确定 ...