Element UI 多选表格【翻页多选】全能版(含翻页多选数据反显、toggleRowSelection失效的原因解析和解决方案)

简介: Element UI 多选表格【翻页多选】全能版(含翻页多选数据反显、toggleRowSelection失效的原因解析和解决方案)

效果预览

实现思路

data中定义 selectedList 数组保存选中的数据

在页面初次渲染、翻页、切换每页数据数量等每次重新获取表格数据渲染表格时,都根据 selectedList 勾选表格中已经选中的行

切换单行勾选状态时,判断是选中还是取消选中,选中则增加选中项,取消选中则移除选中项。

切换全选和取消全选时,根据当前页选中行的数据进行更新,若选中行已在 selectedList 中则不再重复添加,否则添加,对于其他非选中行若已在selectedList 中,则从 selectedList 中移除。

技术难点

1. 不能使用 selection-change 的原因

selection-change 的参数为当前页选中的所有行,在每次重新获取数据渲染表格时(如翻页时),参数为一个空数组,会导致历史选中的数据被清空!

即便使用 :reserve-selection="true" 来保留历史选中记录也无法达到预期效果。

2. toggleRowSelection失效的原因解析和解决方案

toggleRowSelection失效通常为以下两种情况:

(1)表格数据发生变化,表格还没渲染完便执行了toggleRowSelection

解决方案 : 在 $nextTick 中执行 toggleRowSelection

// toggleRowSelection 需在$nextTick中使用!
this.$nextTick(() => {
  this.$refs.multipleTable.toggleRowSelection(row);
});

(2)toggleRowSelection的第一个参数不是表格源数据

即便数据的值完全一样也会失效,因为数据为引用类型,必须地址一样。

解决方案 :toggleRowSelection的第一个参数通过在表格数据中通过 find() 查找得到。

  this.$nextTick(() => {
    this.$refs.multipleTable.toggleRowSelection(
      // 此处必须在 tableData 中查找对应的数据,否则 toggleRowSelection 会失效
      this.tableData.find((row) => {
        return row[this.UID] === item[this.UID];
      }),
      false
    );
  });

完整范例代码

<template>
  <div class="mainBox">
    <h3>已选择:</h3>
    <el-tag
      :key="item[UID]"
      v-for="(item, index) in selectedList"
      closable
      @close="removeItemByIndex(index, item)"
    >
      {{ item.name }}
    </el-tag>

    <el-table
      v-loading="loading"
      ref="multipleTable"
      :data="tableData"
      @select="selectChange"
      @select-all="selectAllChange"
    >
      <el-table-column type="selection" width="55" align="center">
      </el-table-column>
      <el-table-column prop="ID" label="编号" align="center"> </el-table-column>
      <el-table-column prop="name" label="姓名" align="center">
      </el-table-column>
      <el-table-column prop="age" label="年龄" align="center">
      </el-table-column>
    </el-table>
    <el-row type="flex" class="pageBanner" justify="center">
      <el-pagination
        background
        :total="total"
        :page-size="pageSize"
        @size-change="pageSizeChange"
        @current-change="currentPageChange"
        :current-page="currentPage"
        :page-sizes="[1, 2, 3]"
        layout="total, sizes, prev, pager, next, jumper"
      >
      </el-pagination>
    </el-row>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 唯一标识符
      UID: "ID",
      loading: false,
      total: 0,
      pageSize: 3,
      currentPage: 1,
      selectedList: [
        {
          ID: 1,
          name: "王小虎",
          age: 10,
        },
      ],
      tableData: [],
    };
  },

  mounted() {
    // 页面初始化时,首次加载数据
    this.getData(this.currentPage, this.pageSize);
  },

  methods: {
    // 单行前的勾选状态切换
    selectChange(selectedRows, row) {
      // true为选中, 0或false为取消选中
      let selected = selectedRows.length && selectedRows.indexOf(row) !== -1;
      if (selected) {
        this.addItem(row);
      } else {
        this.removeItem(row);
      }
    },
    // 全选/取消全选
    selectAllChange(selectedRows) {
      let selectedMarkList = this.selectedList.map((item) => item[this.UID]);
      // 当前页选中行的标记列表
      let pageSelectedMarkList = Array.isArray(selectedRows)
        ? selectedRows.map((item) => item[this.UID])
        : [];

      this.tableData.forEach((row) => {
        if (pageSelectedMarkList.includes(row[this.UID])) {
          if (!selectedMarkList.includes(row[this.UID])) {
            this.addItem(row);
          }
        } else if (selectedMarkList.includes(row[this.UID])) {
          this.removeItem(row);
        }
      });
    },
    // 切换每页显示条数
    pageSizeChange(newPageSize) {
      this.pageSize = newPageSize;
      this.getData(this.currentPage, this.pageSize);
    },
    // 切换页码--翻页
    currentPageChange(newPage) {
      this.currentPage = newPage;
      this.getData(this.currentPage, this.pageSize);
    },
    // 更新勾选标记
    updateMark() {
      let selectedMarkList = this.selectedList.map((item) => item[this.UID]);

      this.tableData.forEach((row) => {
        if (selectedMarkList.includes(row[this.UID])) {
          // toggleRowSelection 需在$nextTick中使用!
          this.$nextTick(() => {
            this.$refs.multipleTable.toggleRowSelection(row);
          });
        }
      });
    },

    // 模拟访问接口获取数据
    getData(page, pageSize) {
      this.loading = true;
      setTimeout(() => {
        let data = [
          {
            ID: 1,
            name: "王小虎",
            age: 10,
          },
          {
            ID: 2,
            name: "张三",
            age: 20,
          },
          {
            ID: 3,
            name: "李四",
            age: 30,
          },
          {
            ID: 4,
            name: "何香",
            age: 18,
          },
          {
            ID: 5,
            name: "刘刀",
            age: 27,
          },
          {
            ID: 6,
            name: "关胜",
            age: 33,
          },
          {
            ID: 7,
            name: "齐巧",
            age: 55,
          },
          {
            ID: 8,
            name: "卢一方",
            age: 45,
          },
          {
            ID: 9,
            name: "王兴海",
            age: 66,
          },
          {
            ID: 10,
            name: "全德",
            age: 100,
          },
        ];

        this.total = data.length;
        let startIndex = pageSize * (page - 1);
        let endIndex = pageSize * page;
        this.tableData = data.slice(startIndex, endIndex);
        this.updateMark();
        this.loading = false;
      }, 1000);
    },
    // 新增选中项
    addItem(item) {
      this.selectedList.push(item);
    },
    // 移除选中项
    removeItem(item) {
      for (let [index, itemTemp] of this.selectedList.entries()) {
        if (itemTemp[this.UID] === item[this.UID]) {
          this.removeItemByIndex(index);
          break;
        }
      }
    },
    // 根据下标移除选中项
    removeItemByIndex(index, item) {
      this.selectedList.splice(index, 1);

      // 若有item,则是点击标签上的关闭按钮,移除选中项
      if (item) {
        this.$nextTick(() => {
          this.$refs.multipleTable.toggleRowSelection(
            // 此处必须在 tableData 中查找对应的数据,否则 toggleRowSelection 会失效
            this.tableData.find((row) => {
              return row[this.UID] === item[this.UID];
            }),
            false
          );
        });
      }
    },
  },
};
</script>
<style  scoped>
.mainBox {
  margin: 30px;
}
.el-tag {
  margin: 10px;
}
.pageBanner {
  margin: 10px;
}
</style>

化为己用

若你的唯一标识符不是 ID,则修改 data() 中的UID 的值即可!

      // 唯一标识符
      UID: "ID",

目录
相关文章
|
11月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
610 3
|
6月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
6月前
|
算法 前端开发 定位技术
地铁站内导航系统解决方案:技术架构与核心功能设计解析
本文旨在分享一套地铁站内导航系统技术方案,通过蓝牙Beacon技术与AI算法的结合,解决传统导航定位不准确、路径规划不合理等问题,提升乘客出行体验,同时为地铁运营商提供数据支持与增值服务。 如需获取校地铁站内智能导航系统方案文档可前往文章最下方获取,如有项目合作及技术交流欢迎私信我们哦~
371 1
|
8月前
|
Serverless 对象存储 人工智能
智能文件解析:体验阿里云多模态信息提取解决方案
在当今数据驱动的时代,信息的获取和处理效率直接影响着企业决策的速度和质量。然而,面对日益多样化的文件格式(文本、图像、音频、视频),传统的处理方法显然已经无法满足需求。
309 4
智能文件解析:体验阿里云多模态信息提取解决方案
|
8月前
|
文字识别 开发者 数据处理
多模态数据信息提取解决方案评测报告!
阿里云推出的《多模态数据信息提取》解决方案,利用AI技术从文本、图像、音频和视频中提取关键信息,支持多种应用场景,大幅提升数据处理效率。评测涵盖部署体验、文档清晰度、模板简化、示例验证及需求适配性等方面。方案表现出色,部署简单直观,功能强大,适合多种业务场景。建议增加交互提示、多语言支持及优化OCR和音频转写功能...
289 3
多模态数据信息提取解决方案评测报告!
|
10月前
「Mac畅玩鸿蒙与硬件29」UI互动应用篇6 - 多选问卷小应用
本篇将带你实现一个多选问卷小应用,用户可以勾选选项并点击提交按钮查看选择的结果。通过本教程,你将学习如何使用 Checkbox 组件、动态渲染列表、状态管理及用户交互,构建完整的应用程序。
145 1
「Mac畅玩鸿蒙与硬件29」UI互动应用篇6 - 多选问卷小应用
|
10月前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
481 3
|
10月前
|
存储 人工智能 自然语言处理
高效档案管理案例介绍:文档内容批量结构化解决方案解析
档案文件内容丰富多样,传统人工管理耗时低效。思通数科AI平台通过自动布局分析、段落与标题检测、表格结构识别、嵌套内容还原及元数据生成等功能,实现档案的高精度分块处理和结构化存储,大幅提升管理和检索效率。某历史档案馆通过该平台完成了500万页档案的数字化,信息检索效率提升60%。
342 5
|
10月前
|
存储
文件太大不能拷贝到U盘怎么办?实用解决方案全解析
当我们试图将一个大文件拷贝到U盘时,却突然跳出提示“对于目标文件系统目标文件过大”。这种情况让人感到迷茫,尤其是在急需备份或传输数据的时候。那么,文件太大为什么会无法拷贝到U盘?又该如何解决?本文将详细分析这背后的原因,并提供几个实用的方法,帮助你顺利将文件传输到U盘。
|
10月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
167 3

热门文章

最新文章

推荐镜像

更多
  • DNS