数据量庞大的分页穿梭框实现

博客地址:https://ainyi.com/#/63

昨天偶然看到评论区一位老哥的需求,一时兴起,就答应了当天写好源码写个博客

回来的晚,第二天才写好。。

写个分页的穿梭框,从而解决数据量庞大的问题

我之前写过一篇博客:关于 Element 组件的穿梭框的重构 介绍并实现的方法

但是第二个分页的 demo 没有,在上一家公司匆匆解决后,没有写入自己的 GitHub,有点可惜...

当时可是在上班,而且太忙了,不过既然答应了这位老哥写个 demo,就要做到,也是给自己一个挑战

进入正题

看实现效果图

既然之前博客谈过,这里就不仔细谈了,主要放主要的源码

问题

Element 官方组件目前(==18年==)明显对于多选==三级联动的穿梭框==没有解决方案,也对==数据量庞大的穿梭框==没有结局方案(各位看官可以试一下,放入几千条数据到穿梭框,卡到爆...),遂只能自己重写组件,完成业务需求

功能

  1. 实现分页
  2. 搜索,做成在所有数据里搜索,不是在当前分页的数据里搜索,这样就不用在每个分页都搜索一次了。搜索后的结果也会自动分页。(全部数据和仅作展示的数据存都是存放在不同变量)
  3. 全选只在当前页里的全选
  4. 穿梭框左右两个框的联动

关键点

  1. 每个框作为一个子组件(组件化思想)
  2. 分页关键判断临界点
  3. 搜索,监听 keyword 的变化,传递到父组件搜索,从全局数据搜索
  4. 把备选的数据当做已选的过滤数组,把已选的数据当做备选的过滤数组,在全局 data 进行过滤,最后再进行一次搜索(备选、已选)(考虑到是在搜索过后点击的)
  5. 中间的左右箭头(加入已选和移除已选)放在父组件控制数据流动
  6. 数据流动:子备选框 -> 父组件 -> 子已选框 (移除已选相反)

源码

  1. Districts.vue(包裹两个穿梭框的父组件)
export default {
  props: {
    data: {
      type: Array,
    },
  },
  data () {
    return {
      dataList: [], // 未选中(已过滤出已选)的数据
      selectList: [], // 已选中的数据,传递到子组件的数据

      dataListNoCheck: [], // 未选中的(或已搜索)传递到子组件的数据
      selectListCheck: [], // 已选中的(或已搜索)传递到子组件的数据

      checkData: [], // 已勾选的数据(待添加或删除数据)

      noSelectkeyword: ‘‘,
      haSelectkeyword: ‘‘,

      disablePre: true,
      disableNex: true,
    };
  },
  created () {
    this.getDistrict();
  },
  methods: {
    // 分页数据
    getDistrict () {
      this.dataList = this.data;
      this.dataListNoCheck = this.dataList;
    },
    searchWord (keyword, titleId) {
      // 过滤掉数据,保留搜索的数据
      if (titleId === 0) {
        this.noSelectkeyword = keyword;
        this.dataListNoCheck = this.dataList.filter(val => val.name.includes(keyword));
      } else {
        this.haSelectkeyword = keyword;
        this.selectListCheck = this.selectList.filter(val => val.name.includes(keyword));
      }
      let refsName = titleId === 0 ? ‘noSelect‘ : ‘hasSelect‘;
      // 延迟执行
      setTimeout(() => {
        this.$refs[refsName].getDistrict();
      }, 0);
    },
    // 检查左右按钮可用性
    checkDisable (data, id) {
      if (id === 0) {
        data.length > 0 ? (this.disableNex = false) : (this.disableNex = true);
      } else {
        data.length > 0 ? (this.disablePre = false) : (this.disablePre = true);
      }
    },
    // 选择
    checkSelect (val) {
      this.checkData = val;
    },
    // 关键:把未选择的数据当做已选择的过滤数组,把已选择的数据当做未选择的过滤数组,在全局data进行过滤,最后进行一次搜索
    // 添加至已选
    addData () {
      let dataFilter = [
        ...this.selectList,
        ...this.checkData,
      ];
      this.dataList = this.data.filter(item1 => {
        return dataFilter.every(item2 => item2 !== item1);
      });
      this.selectList = this.data.filter(item1 => {
        return this.dataList.every(item2 => item2 !== item1);
      });
      // 搜索一次
      this.searchWord(this.noSelectkeyword, 0);
      this.searchWord(this.haSelectkeyword, 1);
    },
    // 从已选中删除
    deleteData () {
      let dataFilter = [
        ...this.dataList,
        ...this.checkData,
      ];
      this.selectList = this.data.filter(item1 => {
        return dataFilter.every(item2 => item2 !== item1);
      });
      this.dataList = this.data.filter(item1 => {
        return this.selectList.every(item2 => item2 !== item1);
      });
      // 搜索一次
      this.searchWord(this.noSelectkeyword, 0);
      this.searchWord(this.haSelectkeyword, 1);
    },
  },
  components: {
    Transfer,
  },
};
</script>
  1. Transfer.vue(穿梭框子组件)
export default {
  props: {
    titleId: {
      type: Number,
    },
    districtList: { // 父组件传递的数据
      type: Array,
    },
  },
  data () {
    return {
      title: [‘渠道‘, ‘已选中‘],
      districtListMock: [], // 展示的数据 (搜索和分页会自动修改这个数组)
      checkedCities: [], // 已选择,数据格式:[id,id,id...]
      isIndeterminate: false,
      checkAll: false,
      searchWord: ‘‘,
      len: 0,
      total: 0,
      pageIndex: 0,
      disabledPre: true,
      disabledNex: false,
    };
  },
  created () {
    this.getDistrict();
  },
  watch: {
    // 搜索框的监听器
    searchWord (newWord) {
      this.$emit(‘search-word‘, newWord, this.titleId);
    },
    // districtListMock 和 checkAll 的监听器
    districtListMock () {
      // 当方框中无已选择的数据时,不能勾选checkBox
      if (this.checkedCities.length === 0) {
        this.checkAll = false;
        this.isIndeterminate = false;
      }
    },
    checkedCities (newWord) {
      this.$emit(‘check-disable‘, newWord, this.titleId);
    },
    // 当列表中无数据时,不能勾选checkBox
    checkAll () {
      this.checkAll = this.districtListMock.length === 0 ? false : this.checkAll;
    },
  },
  methods: {
    // 分页数据
    getDistrict () {
      this.len = this.districtList.length;
      this.total = Math.ceil(this.len / 200);
      this.pageIndex = 0;
      this.pageData();
    },
    pageData () {
      this.checkedCities = [];
      if (this.total > 1 && this.pageIndex < (this.total - 1)) {
        this.pageIndex === 0 ? this.disabledPre = true : this.disabledPre = false;
        this.disabledNex = false;
        this.districtListMock = this.districtList.slice(this.pageIndex \\* 200, this.pageIndex \\* 200 + 200);
      } else {
        this.total > 1 ? this.disabledPre = false : this.disabledPre = true;
        this.disabledNex = true;
        this.districtListMock = this.districtList.slice(this.pageIndex \\* 200, this.len);
      }
    },
    // 上一页
    prev () {
      this.pageIndex > 0 && --this.pageIndex;
      this.pageData();
    },
    // 下一页
    next () {
      this.pageIndex <= (this.total - 1) && ++this.pageIndex;
      this.pageData();
    },
    // 单选
    handleCheckedChange (value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.districtListMock.length;
      this.isIndeterminate = checkedCount > 0 && checkedCount < this.districtListMock.length;
      // 子传父
      this.$emit(‘check-district‘, value);
    },
    // 全选
    handleCheckAllChange (val) {
      this.checkedCities = val ? this.districtListMock.map(val => val) : [];
      this.isIndeterminate = false;
      // 子传父
      this.$emit(‘check-district‘, this.checkedCities);
    },
  },
};
</script>

具体源码可前往 Github:https://github.com/Krryxa/my-transfer

欢迎 start

呼呼,双休好好休息了~~

博客地址:https://ainyi.com/#/63

原文地址:https://www.cnblogs.com/ainyi/p/10125443.html

时间: 2024-10-08 14:12:46

数据量庞大的分页穿梭框实现的相关文章

数据量你造吗-JAVA分页

数据量你造吗-JAVA分页 原创地址:   http://www.cnblogs.com/Alandre/  (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks 学习的心态第一,解行要相应.其实<弟子规>在"余力学文"当中,一开头就强调了这一个重点."不力行,但学文,长浮华,成何人",这个没有侥幸的,只要学了不去做,无形当中就会增长傲慢,自己不知道.-<弟子规> Written In The Font JAVA-Web 基础那块,我自己也

大数据量下的分页解决方法

最好的办法是利用sql语句进行分页,这样每次查询出的结果集中就只包含某页的数据内容.再sql语句无法实现分页的情况下,可以考虑对大的结果集通过游标定位方式来获取某页的数据. sql语句分页,不同的数据库下的分页方案各不一样,下面是主流的三种数据库的分页sql: sql server: String sql = "select top " + pageSize + " * from students where id not in" + "(select t

对于数据量庞大的下拉菜单建立对应的联想查询

*效果展示:[如图左边为项目信息的下拉菜单,在其右边有一个输入框.实现效果在右边输入框的位置,输入"A",在昨天的下拉框信息中值显示"A"对应的信息] *功能实现: [jsp页面功能实现:] 获取你要的所有项目信息 <% List project_list = (List)request.getAttribute("project_list"); %> js组装成信息数组 <SCRIPT LANGUAGE="JavaS

MySQL大数据量分页查询方法及其优化

方法1: 直接使用数据库提供的SQL语句 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N 适应场景: 适用于数据量较少的情况(元组百/千级) 原因/缺点: 全表扫描,速度会很慢 且 有的数据库结果集返回不稳定(如某次返回1,2,3,另外的一次返回2,1,3). Limit限制的是从结果集的M位置处取出N条输出,其余抛弃. 方法2: 建立主键或唯一索引, 利用索引(假设每页10条) 语句样式: MySQL中,可用如下方法: SELECT * FRO

【转】大数据量分页写法

mysql大数据量使用limit分页,随着页码的增大,查询效率越低下. 测试实验 1.   直接用limit start, count分页语句, 也是我程序中用的方法: select * from product limit start, count当起始页较小时,查询没有性能问题,我们分别看下从10, 100, 1000, 10000开始分页的执行时间(每页取20条), 如下: select * from product limit 10, 20   0.016秒select * from p

Access数据库大数据量的相关测试分析

[e良师益友网]在使用Access 数据库无须开专门的数据库空间,调用,迁移也方便,节省费用.另外对网站搭建者的专业能力要求也相对低一些.但随着网站的运行,数据库体积越来越大,数据 量也从最初的几百条到了现在的上万条,上十万条甚至更多.于是因数据应用级别的改变带来的各种各样的应用问题出现了.而其中大数据量的列表分页效率问题更 是让很多人头疼.小编我随便通过“大数据量分页效率”,“access 分页”等关键词分别百度一下,发现有此疑问的大有人在.很多网页上也给出了不同的解决办法.那么,这些方法到底

数据库有百万数据量的情况下,分页查询的方法及其优化方式

当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点. 下面简单说一下我知道的一些方法. 准备工作 为了对下面列举的一些优化进行测试,下面针对已有的一张表进行说明. 表名:order_history 描述:某个业务的订单历史表 主要字段:unsigned int id,tinyint(4) int type 字段情况:该表一共37个字段,不包含text等大型数据,最大为varch

sql优化之大数据量分页查询(mysql)

当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时就需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点. 谈优化前的准备工作 为了对下面列举的一些优化进行测试,需要使用已有的一张表作为实际例子. 表名:order_history. 描述:某个业务的订单历史表. 主要字段:unsigned int id,tinyint(4) int type. 字段情况:该表一共37个字段,不包含text等大型数据,最大为varchar(500

采用Kettle分页处理大数据量抽取任务

作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5524614.html 需求: 将Oracle数据库中某张表历史数据导入MySQL的一张表里面. 源表(Oracle):table1 目标表(MySQL):table2 数据量:20,000,000 思路: 由于服务器内存资源有限,所以,无法使用Kettle一次性从源表导入目标表千万级别的数据,考虑采用分页导入的方式来进行数据传输,即: 根据实际情况设置一个每次处理的数据量,比如:5,000条,然后