Element UI 实战:跨页保存表格选中状态与判断状态可选性的高效方案

news2025/1/18 20:32:09

引言

        在前文中,我们曾深入探讨了在修改数据后跨页时提醒用户可能丢失数据的问题。虽然这种方式对于一些场景是足够的,但当涉及选择框时,我们需要更为智能和高效的解决方案。在本文中,我们将分享一种基于 Element UI 的实际案例,旨在实现跨页保存选中项与禁选特定项的需求。通过以下详细讨论,你将了解到这一方案的实现原理及其用户体验效果。

问题背景

        在许多 Web 应用中,数据分页是常见的操作方式。当用户在一个页面中选择了一些数据项,然后切换到另一页时,保持之前选中的项通常是用户友好的体验。同时,可能存在一些需要禁选的执行项,例如在某些状态下,用户不应该选择或执行某些操作:如当数据可以进行执行相关操作,并且需要消耗一定时间时,我们为了任务的完整执行,会在任务执行期间,禁止选中该任务的选择框(可以预防用户进行删除等操作),后续执行完毕可以恢复初始选中状态,也可以放弃选中状态。

方案设计与实现

        在 Element UI 中,表格(Table)组件提供了丰富的特性和事件。可以利用这些特性和事件来实现跨页保存选中项和禁选执行项的需求。

实现

        1.跨页保存

        在许多 Web 应用中,数据分页是常见的操作方式。当用户在一个页面中选择了一些数据项,然后切换到另一页时,保持之前选中的项通常是用户友好的体验。

        模板
    <el-table
      ref="multipleTable"
      :data="tableData"
      @select="handleSelectionChange"
      @select-all="handleSelectionAll"
    >
      <el-table-column type="selection" align="center"></el-table-column>
      <el-table-column prop="name" label="name" align="center"></el-table-column>
      <el-table-column prop="age" label="age" align="center"></el-table-column>
    </el-table>
    
    <el-pagination
      :background="true"
      :current-page.sync="queryParams.page"
      :page-size.sync="queryParams.pageSize"
      layout="total,prev,pager,next,sizes"
      :total="total"
      :page-sizes="[5, 10, 20, 40]"
      @size-change="getList"
      @current-change="getList" />
        脚本
data() {
    return {
      total: void 0,
      queryParams: {
        page: 1,
        pageSize: 10,
      },
      allData: [],
      tableData: [],
      multipleSelection: [],
      listId: [],
    };
  },
  mounted() {
    this.getList();
  },
  methods: {
    getList() {
      this.allData = [
        { name: 'A', age: 1 },
        { name: 'B', age: 2 },
        { name: 'C', age: 3 },
        { name: 'D', age: 4 },
        { name: 'E', age: 5 },
        { name: 'F', age: 6 },
        { name: 'G', age: 7 },
        { name: 'H', age: 8 },
        { name: 'I', age: 9 },
        { name: 'J', age: 10 },
        { name: 'K', age: 11 },
        { name: 'L', age: 12 },
        { name: 'M', age: 13 },
        { name: 'N', age: 14 },
        { name: 'O', age: 15 },
        { name: 'P', age: 16 },
        { name: 'Q', age: 17 },
        { name: 'R', age: 18 },
        { name: 'S', age: 19 },
        { name: 'T', age: 20 },
        { name: 'U', age: 21 },
        { name: 'V', age: 22 },
        { name: 'W', age: 23 },
        { name: 'X', age: 24 },
        { name: 'Y', age: 25 },
        { name: 'Z', age: 26 },
      ];

      this.total = this.allData.length;
      let currentPageIndex = (this.queryParams.page - 1) * this.queryParams.pageSize;
      let currentPageSize = this.queryParams.pageSize - 1 || 1;
      this.tableData = this.allData.slice(currentPageIndex, currentPageIndex + currentPageSize + 1);

      this.listId = [];
      this.tableData.forEach(item => this.listId.push(item.name));

      this.$nextTick(() => {
        this.tableData.forEach((item, index) => {
          if (this.multipleSelection.findIndex(v => v == item.name) >= 0) {
            this.$refs.multipleTable.toggleRowSelection(this.$refs.multipleTable.data[index], true);
          }
        });
      });
    },

    // 全选
    handleSelectionAll(val) {
      if (val.length) {
        const result = [];
        this.listId.forEach(id => {
          if (this.multipleSelection.every(item => item !== id)) result.push(id);
        });

        this.multipleSelection.push(...result);
      } else {
        this.listId.forEach(id => {
          this.multipleSelection = this.multipleSelection.filter(item => item !== id);
        });
      }
    },

    // 单选
    handleSelectionChange(rows, row) {
      if (this.multipleSelection.find(item => item === row.name)) this.multipleSelection = this.multipleSelection.filter(item => item != row.name); // 过滤(删除)
      else this.multipleSelection.push(row.name);
    },
}
        解析
  1. getList 方法:

    • 发送 HTTP GET 请求,获取数据(/.../是请求的地址,queryParams是请求参数)。
    • 在请求成功的回调中,判断返回数据的状态是否为200,如果是,将返回的数据赋值给 tableData
    • 构建 listId 数组,存储 tableData 中每一项的 id
    • 利用 $nextTick,确保在 Vue 更新 DOM 后执行,遍历 tableData,对于已经在 multipleSelection 中的项,在表格中选中对应的行。
  2. handleSelectionAll 方法:

    • 接受一个参数 val,即当前页选中的所有行数据。
    • 如果 val.length 大于 0,表示当前页有选中的行,遍历 listId,将不在 multipleSelection 中的项添加到 multipleSelection 中。
    • 如果 val.length 为 0,表示当前页没有选中的行,遍历 listId,将在 multipleSelection 中的项从中移除。
  3. handleSelectionChange 方法:

    • 接受两个参数,rows 是当前页选中的所有行数据,row 是当前操作的行数据。
    • 如果 multipleSelection 中已经存在 row.id,则将其从 multipleSelection 中移除,否则将其添加到 multipleSelection 中。

        这些方法共同实现了跨页保存选中状态的功能,通过维护 multipleSelection 数组来保存用户选择的行的 id,从而在表格分页切换时保持选中状态。

        2.禁选执行项

        数据拥有执行状态之类的字段,并且需要消耗一定时间时,我们为了任务的完整执行,会在任务执行期间,禁止选中该任务的选择框(以避免删除等操作)。执行完毕后可以恢复初始选中状态,也可以放弃选中状态。

         以下代码选择的是后者,即在重新开始运行时,禁用该项选择框并且执行完毕后不重新选中。如果希望保留,在对应执行的函数(下述为 reloadTask)中不删除 multipleSelection 中对应的id即可。

        模板
    <el-table
      ref="multipleTable"
      :data="tableData"
      @select="handleSelectionChange"
      @select-all="handleSelectionAll"
    >
      <el-table-column type="selection" align="center" :selectable="selectable"></el-table-column>
      <el-table-column prop="name" label="name" align="center"></el-table-column>
      <el-table-column prop="age" label="age" align="center"></el-table-column>
      <el-table-column label="status">
        <template slot-scope="scope">
          <span
            style="margin-right:10px; cursor: pointer;"
            :class="scope.row.status !== '执行中' ? 'el-icon-caret-right' : 'el-icon-loading'"
            size="small"
            :disabled="scope.row.status === '执行中'"
            @click="reloadTask(scope.row)"></span>
          <el-tag :type="scope.row.status !== '执行中' ? '' : 'info'">{{scope.row.status}}</el-tag>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      :background="true"
      :current-page.sync="queryParams.page"
      :page-size.sync="queryParams.pageSize"
      layout="total,prev,pager,next,sizes"
      :total="total"
      :page-sizes="[5, 10, 20, 40]"
      @size-change="getList"
      @current-change="getList" />
        脚本
data() {
    return {
      total: void 0,
      queryParams: {
        page: 1,
        pageSize: 10,
      },
      allData: [],
      tableData: [],
      multipleSelection: [],
      listId: [],
      loadingSelection: new Set(),
    };
  },
  mounted() {
    this.getList();
  },
  methods: {
    getList(flag = false) {
      if (!flag) {
        this.allData = [
          { name: 'A', age: 1, status: '执行完毕' },
          { name: 'B', age: 2, status: '执行中' },
          { name: 'C', age: 3, status: '执行完毕' },
          { name: 'D', age: 4, status: '未执行' },
          { name: 'E', age: 5, status: '未执行' },
          { name: 'F', age: 6, status: '执行中' },
          { name: 'G', age: 7, status: '执行中' },
          { name: 'H', age: 8, status: '执行中' },
          { name: 'I', age: 9, status: '执行中' },
          { name: 'J', age: 10, status: '未执行' },
          { name: 'K', age: 11, status: '未执行' },
          { name: 'L', age: 12, status: '未执行' },
          { name: 'M', age: 13, status: '未执行' },
          { name: 'N', age: 14, status: '未执行' },
          { name: 'O', age: 15, status: '未执行' },
          { name: 'P', age: 16, status: '未执行' },
          { name: 'Q', age: 17, status: '未执行' },
          { name: 'R', age: 18, status: '未执行' },
          { name: 'S', age: 19, status: '未执行' },
          { name: 'T', age: 20, status: '未执行' },
          { name: 'U', age: 21, status: '未执行' },
          { name: 'V', age: 22, status: '未执行' },
          { name: 'W', age: 23, status: '未执行' },
          { name: 'X', age: 24, status: '未执行' },
          { name: 'Y', age: 25, status: '未执行' },
          { name: 'Z', age: 26, status: '未执行' },
        ];
      }

      this.total = this.allData.length;
      let currentPageIndex = (this.queryParams.page - 1) * this.queryParams.pageSize;
      let currentPageSize = this.queryParams.pageSize - 1 || 1;
      this.tableData = this.allData.slice(currentPageIndex, currentPageIndex + currentPageSize + 1);

      this.listId = [];
      this.tableData.forEach(item => this.listId.push(item.name));

      this.$nextTick(() => {
        this.tableData.forEach((item, index) => {
          if (this.multipleSelection.findIndex(v => v == item.name) >= 0) {
            this.$refs.multipleTable.toggleRowSelection(this.$refs.multipleTable.data[index], true);
          }
        });
      });
    },

    // 执行任务
    reloadTask(row) {
      this.multipleSelection = this.multipleSelection.filter(item => item !== row.name);
      row.status = '执行中';
      this.getList(true);
    },
    
    // 判断可选性
    selectable(row) {
      if (row.status !== '执行中') {
        if (this.loadingSelection.has(row.name)) this.loadingSelection.delete(row.name);
        return true;
      } else {
        this.loadingSelection.add(row.name);
        return false;
      }
    },

    // 全选
    handleSelectionAll(val) {
      if (val.length) {
        const result = [];
        this.listId.forEach(id => {
          if (this.multipleSelection.every(item => item !== id) && !this.loadingSelection.has(id)) result.push(id);
        });

        this.multipleSelection.push(...result);
      } else {
        this.listId.forEach(id => {
          this.multipleSelection = this.multipleSelection.filter(item => item !== id);
        });
      }
    },

    // 单选
    handleSelectionChange(rows, row) {
      if (this.multipleSelection.find(item => item === row.name)) this.multipleSelection = this.multipleSelection.filter(item => item != row.name); // 过滤(删除)
      else this.multipleSelection.push(row.name);
    },
  },
         解析

        这部分代码经过修改后主要涉及到对行的可选性(selectable 方法)以及全选处理(handleSelectionAll 方法)。下面是对修改部分代码的详细解释:

  1. selectable 方法:

    • selectable 方法用于确定给定行 row 是否可选。如果行的状态 status 不是 '执行中',则认为该行可选。
    • 如果行不可选,而且 loadingSelection 集合中已经存在该行的 id,则将其从 loadingSelection 中删除,表示加载完成。
    • 如果行可选,将其 id 添加到 loadingSelection 集合中,表示正在加载中,并返回 false 表示不可选;否则,返回 true 表示可选。
  2. handleSelectionAll 方法:

    • 该方法用于处理全选操作。接收参数 val,即当前页选中的所有行数据。
    • 如果有选中的行,遍历 listId,将不在 multipleSelection 中且不在 loadingSelection 中的项添加到 multipleSelection 中。
    • 如果没有选中的行,遍历 listId,将在 multipleSelection 中的项从中移除。

        这些修改主要增加了对行的可选性的判断,以及对加载状态的管理,通过 loadingSelection 集合来标记哪些行正在加载中。这样可以更好地控制在某些条件下禁止选择或在加载中时保持选择状态。

实现效果

跨页保存

禁选某些状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1280578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

opencv学习二:加载显示图片

文章目录 加载显示图片&#xff08;一&#xff09;函数1.imread()读取图片&#xff08;1&#xff09;matplotlib和opencv中imread函数的区别 加载显示图片 &#xff08;一&#xff09;函数 1.imread()读取图片 Mat imread(const string& filename, int flags1 );第一个参…

ASP.NET-BS结构的城市酒店入住信息管理系统的设计

2 理论基础 2.1 数据库技术 数据库技术应用中&#xff0c;经常用到的基本概念有&#xff1a;数据库&#xff08;DB&#xff09;、数据库管理系统&#xff08;DBMS&#xff09;、数据库系统&#xff08;DBS&#xff09;、数据库技术及数据模型。 数据库技术是研究数据库的结构、…

【Linux服务器Java环境搭建】04 JDK安装(JAVA环境安装)

【Linux服务器Java环境搭建】01购买云服务器以及在服务器中安装Linux系统 【Linux服务器Java环境搭建】02 通过xftp和xshell远程连接云服务器 【Linux服务器Java环境搭建】03 Git工具安装 【Linux服务器Java环境搭建】04 JDK安装&#xff08;JAVA环境安装&#xff09; 【Linux服…

【Linux服务器Java环境搭建】02 通过xftp和xshell远程连接云服务器

【Linux服务器Java环境搭建】01购买云服务器以及在服务器中安装Linux系统 【Linux服务器Java环境搭建】02 通过xftp和xshell远程连接云服务器 【Linux服务器Java环境搭建】03 Git工具安装 【Linux服务器Java环境搭建】04 JDK安装&#xff08;JAVA环境安装&#xff09; 【Linux服…

Linux4.7、环境变量

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 基本概念 见见环境变量 指令原理 常见环境变量及其测试 环境变量相关指令 环境变量组织方式 通过代码获取环境变量 通过系统变量获取环境变量以及设置环境变量 环境变量的全局属性 基本概念 首先&#xff0c;…

深入理解同源限制:网络安全的守护者(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Hdoop学习笔记(HDP)-Part.10 创建集群

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

机器学习笔记 - 什么是3D语义场景完成/补全?

一、什么是3D语义场景补全? 3D 语义场景完成(Semantic Scene Completion)是一种机器学习任务,涉及以体素化形式预测给定环境的完整3D场景(完成3D形状的同时推断场景的 3D 语义分割的任务)。这是通过使用深度图和为场景提供上下文的可选 RGB 图像来完成的。目标是以一种可轻…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《余电上网/制氢方式下微电网系统全生命周期经济性评估》

该标题涉及到对微电网系统的全生命周期经济性进行评估&#xff0c;其重点关注两种运营方式&#xff1a;余电上网和制氢。以下是对标题的解读&#xff1a; 微电网系统&#xff1a; 微电网是指一种小规模的电力系统&#xff0c;通常包括分布式能源资源&#xff08;如太阳能、风能…

搭建 ebpf 开发测试环境

0 内容说明 这部分主要讲述了如何通过官网学习ebpf&#xff0c;以及如何搭建自己的ebpf开发测试环境&#xff0c;主要是需要安装哪些工具链。 1 ebpf在线学习 ebpf官网中提供了一个快速在线学习ebpf的路径&#xff0c;在这个学习平台中一共有两项学习内容&#xff0c;一个是…

ubuntu下快速搭建docker环境训练yolov5数据集

参考文档 yolov5-github yolov5-github-训练文档 csdn训练博客 一、配置环境 1.1 安装依赖包 前往清华源官方地址 选择适合自己的版本替换自己的源 # 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak # 修改源文件 # 更新 sudo apt update &&a…

操作系统期末复习(1)

复习资料 操作系统笔记 操作系统教程书 课程PPT 王道计算机考研 操作系统_哔哩哔哩_bilibili 操作系统部分重点内容 - TinyChens Studio - 互联网技术学习工作经验分享 学校考试题型 一、简答题&#xff08;大概有6道&#xff09; 二、填空题 三、解析题&#xff08;大…

论文阅读——Loss odyssey in medical image segmentation

Loss odyssey in medical image segmentation github&#xff1a;https://github.com/JunMa11/SegLossOdyssey 这篇文章回顾了医学图像分割中的20种不同的损失函数&#xff0c;旨在回答&#xff1a;对于医学图像分割任务&#xff0c;我们应该选择哪种损失函数&#xff1f; 首…

【多线程】-- 10线程同步synchronized方法/块

多线程 6 线程同步 同步方法 由于我们可以通过private关键字来保证数据对象只能被方法访问&#xff0c;所以我们只需要针对方法提出一套机制&#xff0c;这套机制就是synchronized关键字&#xff0c;它包括以下两种用法&#xff1a; ​ synchronized方法和synchronized块 …

C语言--求一个十进制整数中1的个数

一.题目描述⭐ 求一个十进制整数中1的个数 比如&#xff1a; 输入:10201 输出&#xff1a;2 &#xff08;这个数字中1的个数是2&#xff09; 二.思路分析⭐ 数字类的问题我们可以用取模&#xff0c;或者取余运算。 首先定义一个计数器&#xff0c;用来统计1的个数。 输入数字…

Kubernetes实战(六)-多系统架构容器镜像构建实战

1 背景 最近在一个国产化项目中遇到了这样一个场景&#xff0c;在同一个 Kubernetes 集群中的节点是混合架构的&#xff0c;即其中某些节点的 CPU 架构是 x86 的&#xff0c;而另一些节点是 ARM 的。为了让镜像在这样的环境下运行&#xff0c;一种最简单的做法是根据节点类型为…

Python面向对象④:继承【侯小啾python领航班系列(二十二)】

Python面向对象④:继承【侯小啾python领航班系列(二十二)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

随心玩玩(十)git

写在前面&#xff1a;研究生一年多了&#xff0c;一直浑浑噩噩的&#xff0c;在深度学习的泥潭挣扎了好久&#xff0c;终于走出了精神内耗的泥潭…好久没有写博客了&#xff0c;决定重新捡起来…记录一下学习吧~ 之前写了一篇git的博客&#xff0c;【github 从0开始的基本操作…

<蓝桥杯软件赛>零基础备赛20周--第8周第2讲--排序的应用

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

WakaTime一个用于跟踪和分析编程时间的工具

WakaTime是一个用于跟踪和分析编程时间的工具&#xff0c;它可以集成到各种代码编辑器和集成开发环境中&#xff0c;例如Visual Studio Code、Sublime Text、PyCharm等。它可以帮助开发人员了解他们花费在不同项目和编程语言上的时间&#xff0c;以及他们的编码习惯和生产力。 …