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

引言

        在前文中,我们曾深入探讨了在修改数据后跨页时提醒用户可能丢失数据的问题。虽然这种方式对于一些场景是足够的,但当涉及选择框时,我们需要更为智能和高效的解决方案。在本文中,我们将分享一种基于 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 集合来标记哪些行正在加载中。这样可以更好地控制在某些条件下禁止选择或在加载中时保持选择状态。

实现效果

跨页保存

禁选某些状态

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java封装讯飞星火大模型历险记

问题描述与分析 现状描述与目标 在使用讯飞星火大模型API的过程中&#xff0c;API的返回结果在可以在其他线程中进行分次打印&#xff0c;但是在main方法中直接打印返回结果&#xff0c;显示为空。这种情况下不利于二次封装&#xff0c;希望在main方法中获取完整的API返回结果…

【开源视频联动物联网平台】帧率、码率和分辨率

帧率、码率和分辨率是视频和图像处理中的重要概念&#xff0c;它们直接影响到视频的带宽占用和显示效果。在进行视频项目时&#xff0c;根据应用需求对视频参数进行调整是必要的&#xff0c;因此了解这些参数的具体含义和指标是非常重要的。 在进行视频项目时&#xff0c;需要…

实战Flask+BootstrapTable后端传javascript脚本给前端实现多行编辑(ajax方式)

相信看到此文的朋友们一定会感到庆幸,总之我是用了两天死磕,才得到如下结果,且行且珍惜,祝好各位! 话不多说,有图有源码 1.看图 2.前端实现页面 <!DOCTYPE html> {% from "common/_macro.html" import static %} <html> <meta charset"utf-8&…

Python开发运维:PyMongo 连接操作 MongoDB

目录 一、理论 1.PyMongo模块 2.Mongo Shell 二、实验 1. Windows11安装MongoDB 7.0.4 2.Windows11安装MongoDB Shell 2.1.0 3.PyMongo 连接 MongoDB&#xff08;无密码方式&#xff09; 4.PyMongo 连接 MongoDB&#xff08;有密码方式&#xff09; 5.PyMongo 操作 Mo…

rabbitmq消息队列实验

实验目的&#xff1a;实现异步通信 实验条件&#xff1a; 主机名 IP地址 组件 test1 20.0.0.10 rabbitmq服务 test2 20.0.0.20 rabbitmq服务 test3 20.0.0.30 rabbitmq服务 实验步骤&#xff1a; 1、安装rabbitmq服务 2、erlang进入命令行&#xff0c;查看版本 …

zookeeper集群和kafka集群

&#xff08;一&#xff09;kafka 1、kafka3.0之前依赖于zookeeper 2、kafka3.0之后不依赖zookeeper&#xff0c;元数据由kafka节点自己管理 &#xff08;二&#xff09;zookeeper 1、zookeeper是一个开源的、分布式的架构&#xff0c;提供协调服务&#xff08;Apache项目&…

91基于matlab的以GUI实现指纹的识别和匹配百分比

基于matlab的以GUI实现指纹的识别和匹配百分比,中间有对指纹的二值化&#xff0c;M连接&#xff0c;特征提取等处理功能。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 91M连接 特征提取 (xiaohongshu.com)

国产linux单用户模式破解无密码登陆 (麒麟系统用户登录密码遗忘解决办法)

笔者手里有一批国产linu系统&#xff0c;目前开始用在日常的工作生产环境中&#xff0c;我这个老程序猿勉为其难的充当运维的或网管的角色。 国产linux系统常见的为麒麟Linux&#xff0c;统信UOS等&#xff0c;基本都是基于debian再开发的linux。 问题描述&#xff1a; 因为…

Windows系列:windows server 2016 下域环境的搭建(完整版)

windows server 2016 下域环境的搭建&#xff08;完整版&#xff09; windows server 2016 下域环境的搭建在搭建之前简单介绍一下基础知识&#xff1a;一、环境介绍 &#xff1a;1.这里用拓扑图进行展示&#xff1a;2.所有环境配置如下 二、搭建主域&#xff1a;一. 创建主域1…

天眼销:精准的企业名录

企业名录的重要性&#xff0c;对于销售而言都是极其重要的。本期为家人们分享如何正确挑选出优质的企业名录渠道&#xff0c;避免走一些弯弯坑坑。 为了有效利用企业名录进行客户开发&#xff0c;您需要关注信息的准确性、可提供的资源数量以及信息的时效性。能否根据您的需求…

统信UOS和vue.js的一个兼容问题

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 这事到现在说起还很奇怪&#xff0c;在UOS20&#xff08;硬件为华为鲲鹏服务器&#xff0c;arm架构&#xff0c;g8.3&#xff09;上部署uve.js&#xff0…

Windows10中在Visual Studio2017中VC++项目安装使用GoogleTest库

Windows10中在Visual Studio2017中VC项目安装使用GoogleTest库 在Windows10中VC程序中可以不用自己手动下载GoogleTest源代码&#xff0c;可以直接通过【项目】-> 【管理 NuGet 程序包】-> 【浏览】-> 搜索 googletest&#xff0c; 找到Microsoft.googletest.v140.wi…

LabVIEW开发自适应降噪ANC

LabVIEW开发自适应降噪ANC 在许多情况下&#xff0c;信号很嘈杂&#xff0c;必须消除噪声。自适应降噪&#xff08;ANC&#xff09;是可用于消除信号噪声的主要实时方法之一。可以使用LabVIEW自适应滤滤器工具包来设计ANC应用程序。本文介绍使用自适应筛选器工具包的ANC的一些…

GAN:WGAN前作

WGAN前作&#xff1a;有原则的方法来训练GANs 论文&#xff1a;https://arxiv.org/abs/1701.04862 发表&#xff1a;ICLR 2017 本文是wgan三部曲的第一部。文中并没有引入新的算法&#xff0c;而是标是朝着完全理解生成对抗网络的训练动态过程迈进理论性的一步。 文中基本是…

Neo4j 程序开发 JavaAPI 嵌入式开发模式(头歌)

文章目录 第1关&#xff1a;JavaAPI 嵌入式开发模式任务描述相关知识创建 Neo4j 数据库启动 Neo4j 数据事务创建节点创建节点关系将创建的数据库设置为默认数据库 编程要求测试说明答案代码修改配置文件&#xff0c;更改默认 Neo4j 数据库代码文件 第1关&#xff1a;JavaAPI 嵌…

C#开发的OpenRA游戏之属性SelectionDecorations(14)

C#开发的OpenRA游戏之属性SelectionDecorations(14) 前面分析选择类时,还有一个功能,就是把选中物品的状态和生命值显示出来。 它是通过下面的函数来实现: protected override IEnumerable<IRenderable> RenderSelectionBars(Actor self, WorldRenderer wr, bool …

网络安全应急响应-Server2228(环境+解析)

网络安全应急响应 任务环境说明: 服务器场景:Server2228(开放链接)用户名:root,密码:p@ssw0rd123

【稳定检索|投稿优惠】2024年生物神经工程与健康大数据国际会议(ICBNHBD 2024)

2024年生物神经工程与健康大数据国际会议(ICBNHBD 2024) 2024 International Conference on Biological Neuroengineering and Health Big Data(ICBNHBD) 一、【会议简介】 2024年生物神经工程与健康大数据国际会议(ICBNHBD 2024)&#xff0c;这场科学盛宴&#xff0c;会议在中…

开关电源工作时,如何抑制纹波和减小高频噪声?

开关电源的纹波和噪声是一个本质问题&#xff0c;换而言之无论纹波和噪声多么小&#xff0c;也无法从根本上去除&#xff0c;再绝对的讲开关电源无论成本怎么提高&#xff0c;也无法完全达到线性电源的性能和特点。那么&#xff0c;通常抑制或减少它的做法有五种&#xff1a; …

2分图匹配算法

定义 节点u直接无边&#xff0c;v之间无边&#xff0c;边只存在uv之间。判断方法&#xff1a;BFS染色法&#xff0c;全部染色后&#xff0c;相邻边不同色 无权二部图中的最大匹配 最大匹配即每一个都匹配上min&#xff08;u&#xff0c; v&#xff09;。贪心算法可能导致&…