element-ui的穿梭框数据量大时点击“全选”卡顿

element-ui的穿梭框数据量大时点击“全选”卡顿

遇到问题:
数据量小的时候问题还没有暴露,当数据大概有几千条时,点击全选时页面需要大概需要三四秒,单选、移动操作也是如此,对于用户来说体验感很差。
解决办法:
可以将node_modules\element-ui\packages\transfer组件拎出来作为组件,针对组件的方法进行改写,再进行引用。

  1. 修改transfer-panel.vue文件里的updateAllChecked() 全选方法:
updateAllChecked() {
  /*
    this.checkableData是对象数组,需要每个对象里的key
    checkableDataKeys是'所有可以进行选择的item'的key的数组
  */
  // const checkableDataKeys = this.checkableData.map(
  //   (item) => item[this.keyProp]
  // );
  /*
    this.checked是'已经选中的item'的数组
    如果this.checked存在着checkableDataKeys的每一项的话,那么every方法返回true
    allChecked为是否全选,这里是O(n^2)的时间复杂度
  */
  // this.allChecked =
  //   checkableDataKeys.length > 0 &&
  //   checkableDataKeys.every((item) => this.checked.indexOf(item) > -1); 
  
  // 修改
  let checkObj = {};
  /* 含义:如果this.checked=['a','b','c'],那么checkObj={a:true,b:true,c:true} */
  this.checked.forEach((item) => {
    checkObj[item] = true;
  });
  /* 
    含义:item[this.keyProp]为item对象中this.keyProp(属性)的属性值,
    然后使用这个值作为checkObj的属性名来查找。遍历this.checkableData数组,
    如果checkObj对象的所有对应属性都存在(即checkObj[item[this.keyProp]]为true),
    那么every方法返回true 
  */
  this.allChecked =
    this.checkableData.length > 0 &&
    this.checked.length > 0 &&
    this.checkableData.every((item) => checkObj[item[this.keyProp]]);
},

以及单选逻辑:

watch: {
  checked(val, oldVal) {
    this.updateAllChecked();

    // 源码
    // if (this.checkChangeByUser) {
        // O(n^2)的时间复杂度
    //  const movedKeys = val.concat(oldVal).
    //    filter(v => val.indexOf(v) === -1 || oldVal.indexOf(v) === -1);
    //  this.$emit('checked-change', val, movedKeys);
    // } else {
    //   this.$emit('checked-change', val);
    //   this.checkChangeByUser = true;
    // }
    
    // 修改
    let newObj = {};
    val.every((item) => {
      newObj[item] = true;
    });
    let oldObj = {};
    oldVal.every((item) => {
      oldObj[item] = true;
    });
    if (this.checkChangeByUser) {
      // O(n)
      const movedKeys = val
        .concat(oldVal)
        .filter((v) => newObj[v] || oldVal[v]);
      this.$emit("checked-change", val, movedKeys);
    } else {
      this.$emit("checked-change", val);
      this.checkChangeByUser = true;
  }
},
  1. 修改main.vue里的addToRight() 移动方法
addToRight() {
  let currentValue = this.value.slice();
  const itemsToBeMoved = [];
  const key = this.props.key;
   
  // 源码
  // this.data.forEach(item => {
  //   const itemKey = item[key];
      // O(n^2)
  //  if ( 
  //    this.leftChecked.indexOf(itemKey) > -1 && this.value.indexOf(itemKey) === -1
  //  ) {
  //    itemsToBeMoved.push(itemKey);
  //  }
  // }); 

   // 修改
   let leftCheckedKeyPropsObj = {};
     this.leftChecked.forEach((item) => {
       leftCheckedKeyPropsObj[item] = true;
     });
   let valueKeyPropsObj = {};
   this.value.forEach((item) => {
     valueKeyPropsObj[item] = true;
   });
   this.data.forEach((item) => {
     const itemKey = item[key];
     // O(n)
     if ( leftCheckedKeyPropsObj[itemKey] && !valueKeyPropsObj[itemKey]) {
       itemsToBeMoved.push(itemKey);
     }
    });

    currentValue = this.targetOrder === 'unshift'
      ? itemsToBeMoved.concat(currentValue)
      : currentValue.concat(itemsToBeMoved);
    this.$emit('input', currentValue);
    this.$emit('change', currentValue, 'right', this.leftChecked);
}

除此之外,还要优化两个computed:

computed: {
  sourceData() {
    let valueObj = {};
    this.value.forEach((item)=>{
      valueObj[item] = true;
    });
    return this.data.filter(
      (item) => !valueObj[item[this.props.key]]
    );
  },
  targetData() {
    if (this.targetOrder === 'original') {
      let valueObj = {};
      this.value.forEach((item)=>{
        valueObj[item] = true;
      });
      let data = this.data.filter(
        (item) => valueObj[item[this.props.key]]
      );
      return data;
    } else {
      return this.value.reduce((arr, cur) => {
        const val = this.dataObj[cur];
        if (val) {
          arr.push(val);
        }
        return arr;
      }, []);
    }
  }
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值