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",

目录
相关文章
|
6月前
|
Linux Go iOS开发
IDA 9.2 发布:Golang 改进、新 UI 组件、类型解析等
IDA Pro 9.2 (macOS, Linux, Windows) - 强大的反汇编程序、反编译器和多功能调试器
1182 0
|
8月前
|
人工智能 JSON 前端开发
如何解决后端Agent和前端UI之间的交互问题?——解析AG-UI协议的神奇作用
三桥君指出AG-UI协议通过SSE技术实现智能体与前端UI的标准化交互,解决流式传输、实时进度显示、数据同步等开发痛点。其核心功能包括结构化事件流、多Agent任务交接和用户中断处理,具有"一次开发到处兼容"、"UI灵活可扩展"等优势。智能体专家三桥君认为协议将AI应用从聊天工具升级为实用软件,适用于代码生成、多步骤工作流等场景,显著提升开发效率和用户体验。
1880 0
|
10月前
|
自然语言处理 安全 JavaScript
HarmonyOsNEXT【ArkUI超全解析】新手必看的方舟UI框架指南!
本文是HarmonyOS NEXT方舟UI框架新手指南,涵盖ArkTS开发核心知识点。从UI与组件基础概念到声明式开发优势,再到ArkTS代码实战,包括组件创建、属性设置、事件绑定等。通过实例解析自定义组件开发流程,提供避坑技巧与代码风格建议,助你快速掌握ArkUI框架精髓,轻松构建高效、美观的HarmonyOS应用界面。适合初学者及希望转型声明式开发的开发者学习参考。
|
9月前
|
JavaScript 测试技术 Python
UI自动化测试中的元素等待机制解析
在UI自动化测试中,元素定位失败常因页面存在iframe或缺乏合理等待机制。本文解析三种等待策略及其应用场景:显式等待可精确控制单个元素等待条件,支持自定义轮询;隐式等待全局生效,适合简单页面加载;强制等待仅用于临时调试,正式脚本慎用。通过对比三者执行精度、资源消耗及适用场景,帮助选择最优策略,提升测试效率与稳定性。
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
715 4
JSON数据解析实战:从嵌套结构到结构化表格
|
12月前
|
数据采集 前端开发 JavaScript
金融数据分析:解析JavaScript渲染的隐藏表格
本文详解了如何使用Python与Selenium结合代理IP技术,从金融网站(如东方财富网)抓取由JavaScript渲染的隐藏表格数据。内容涵盖环境搭建、代理配置、模拟用户行为、数据解析与分析等关键步骤。通过设置Cookie和User-Agent,突破反爬机制;借助Selenium等待页面渲染,精准定位动态数据。同时,提供了常见错误解决方案及延伸练习,帮助读者掌握金融数据采集的核心技能,为投资决策提供支持。注意规避动态加载、代理验证及元素定位等潜在陷阱,确保数据抓取高效稳定。
377 17
|
12月前
|
JSON 监控 网络协议
Bilibili直播信息流:连接方法与数据解析
本文详细介绍了自行实现B站直播WebSocket连接的完整流程。解析了基于WebSocket的应用层协议结构,涵盖认证包构建、心跳机制维护及数据包解析步骤,为开发者定制直播数据监控提供了完整技术方案。
1383 9
|
12月前
|
缓存 监控 搜索推荐
【实战解析】smallredbook.item_get_video API:小红书视频数据获取与电商应用指南
本文介绍小红书官方API——`smallredbook.item_get_video`的功能与使用方法。该接口可获取笔记视频详情,包括无水印直链、封面图、时长、文本描述、标签及互动数据等,并支持电商场景分析。调用需提供`key`、`secret`和`num_iid`参数,返回字段涵盖视频链接、标题、标签及用户信息等。同时,文章提供了电商实战技巧,如竞品监控与个性化推荐,并列出合规注意事项及替代方案对比。最后解答了常见问题,如笔记ID获取与视频链接时效性等。
|
存储 缓存 监控
如何高效爬取天猫商品数据?官方API与非官方接口全解析
本文介绍两种天猫商品数据爬取方案:官方API和非官方接口。官方API合法合规,适合企业长期使用,需申请企业资质;非官方接口适合快速验证需求,但需应对反爬机制。详细内容涵盖开发步骤、Python实现示例、反爬策略、数据解析与存储、注意事项及扩展应用场景。推荐工具链包括Playwright、aiohttp、lxml等。如需进一步帮助,请联系作者。
|
12月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
1126 29

热门文章

最新文章

推荐镜像

更多
  • DNS