el-tree shift

之前写过一个优化部分代码的el-checkbox 

这次项目要求el-tree写一个shift选项,基本很多依赖的都是element-ui本身的方法,但是踩了一个坑,就是很简单的坑,以为是别的错误,发现后简直哭笑不得,这个坑来给大家填一下。

写一下前期的我的数据结构之类的,供参考!

我的数据结构是三层,项目只有三层的,所以更深层次的大家可以去找一下,或者在我的基础上加以优化,有更优化的可以私信我奥

1: 数据(因为我的数据是从后端拿过来再处理的我简单码一个结构)

[
    { 
        id:"1",
        label: "文字",
        children:[
                {
                  id:"1",
                  label: "文字",
                  children:[
                        {
                          label: "",
                          value: "",
                            id: ""    
                         }

2: 了解我的数据结构后我们开始看代码啦

首先我们必须在el-tree上面设置keys, 建议选择还是用keys,避免数据重复出现错误

node-key="id" 很重要
<el-tree
          ref="tree"
          :data="loadCases"
          show-checkbox
          :check-on-click-node="true"
          node-key="id"
          highlight-current
          :expand-on-click-node="false"
          @check="handleCheckChange"
        />

3: 做好基本工作现在就来写方法吧,使用这个事件获取到属性

4: 这个事件是调用我们的shift事件的把数据抛进去

shiftClick(datas) {
      // 获取选中的节点和半选中节点
      const AllcheckedNodes = this.$refs.tree.getCheckedNodes(false, true);
      // 选中的节点的索引
      const chilIndex = AllcheckedNodes.findIndex(item => item.id === datas.id);
      // 截取索引1 到 选中的之间的数据
      const newAll = AllcheckedNodes.slice(1, chilIndex);
      // 反转数据并拿到的第一个就是当前选中的父节点
      const parent = newAll.reverse().find(item => item.children);
      // 父节点的索引
      const parentIndex = AllcheckedNodes.findIndex(item => item.id === parent.id);
      // 获取父节点后面的所有数据
      const parentAfter = AllcheckedNodes.slice(parentIndex + 1);
      // 当前父元素后面的第一个兄弟索引(反正就是后面的元素,有可能是兄弟也有可能是子元素)
      const parentTwo = parentAfter.find(item => item.children) || parentAfter[parentAfter.length - 1];
      const parentTwoIndex = AllcheckedNodes.findIndex(item => item.id === parentTwo.id);
      // 选中的数组,当前父级之下的数组内的
      const chekbox = AllcheckedNodes.slice(parentIndex + 1, parentAfter.find(item => item.children) ? parentTwoIndex : parentTwoIndex + 1);
        // 这个事件是用来确定第一次按下shift时
      this.checkPinClick(datas, { allList: parent.children || [] });
      const this_ = this;
      setTimeout(() => {
        // 筛选出中间值
        this.selectionChange(chekbox, { allList: parent.children || [], selectData: chekbox });
        setTimeout(() => {
          for (let i = 0; i < chekbox.length; i++) {
              // 选择
            this_.$refs.tree.setChecked(chekbox[i].id, true, false);
          }
        }, 75);
      }, 60);
    },

5:下面的代码是shift事件里面的,我还是用了我上次checkbox 的事件,对于不同数据进行了优化

用mixin引入就好了,数据不一致请自行修改哦

export default {
  data() {
    return {
      starNum: -1, // 作为起点
      pin: false, // 默认为false
      indeterminate: true // checkbox是否可选状态
    };
  },
  watch: {
    pin: {
      handler(val) {
        if (!val) {
          this.starNum = -1;
        }
      }
    }
  },
  mounted() {
    // 监听按下键盘事件
    window.addEventListener("keydown", e => {
      if (e.keyCode === 16 && e.shiftKey) {
        this.pin = true;
      }
    });
    window.addEventListener("keyup", e => {
      this.pin = false;
    });
  },
  methods: {
    // 复选框多选功能
    /**
     * @param checked 选中的
     * @param allList 所有数据
     * @param selectData 返回选中的
     * @param treeCheck  el-tree返回选中的
     */
    selectionChange(checked, { allList, selectData }) {
      const this_ = this;
      setTimeout(() => {
        const data = allList; // 获取所有数据
        const starNum = this.starNum; // 起点数 从-1开始
        const endData = checked[checked.length - 1];
        const endIdx = data.findIndex(item => {
          if (this.stringFlag(item)) {
            if (this.stringFlag(endData)) {
              return item === endData;
            } else {
              return item === endData.label;
            }
          } else {
            if (this.stringFlag(endData)) {
              return item.label === endData;
            } else {
              return item.label === endData.label;
            }
          }
        }); // 终点数
        const dataStarNum = this.stringFlag(data[starNum] || "") ? data[starNum] : data[starNum].label;
        const arraySome = checked.some(item => {
          if (this.stringFlag(item)) {
            return item === dataStarNum;
          } else {
            return item.label === dataStarNum;
          }
        });
        if (this_.pin && arraySome) { // 判断按住
          const sum = Math.abs(starNum - endIdx) + 1; // 这里记录终点
          const min = Math.min(starNum, endIdx); // 这里记录起点
          let i = 0;
          while (i < sum) {
            const index = min + i;
            const dataIndex = this.stringFlag(data[index] || "") ? data[index] : data[index].label;
            const flagIdx = selectData.find(item => this.stringFlag(item) ? item === dataIndex : item.label === dataIndex); // 判断区间内的数据是否已选中
            if (!flagIdx) { // 值是否选中
              selectData.push(this.stringFlag(data[index]) ? dataIndex : data[index]);
            }
            i++;
          }
        }
        return selectData;
      }, 50);
    },
    // 记录第一次按下shift
    checkPinClick(check, { allList }) {
      if (this.pin && this.starNum === -1) {
        this.starNum = allList.findIndex(item => {
          if (typeof (item) === "string") {
            if (typeof (check) === "string") {
              return item === check;
            } else {
              return item === check.label;
            }
          } else {
            if (typeof (check) === "string") {
              return item.label === check;
            } else {
              return item.label === check.label;
            }
          }
        }); // 记录起点
      }
    },
    stringFlag(item) {
      return typeof (item) === "string";
    }
  }
};

到这里就OOOOK啦!

大家注意!!!敲黑板!大坑来啦

在el-tree里面有

setCheckedKeys 和 setChecked 两个设置勾选的方法!

setCheckedKeys: 通过 keys 设置目前勾选的节点,使用此方法必须设置 node-key 属性, 他的意思就是,他会把你之前的其他的选择全部清除掉(传的是数组)

setChecked: 通过 key / data 设置某个节点的勾选状态,使用此方法必须设置 node-key 属性,而这个是设置你所传入的data和keys值的状态,不会清除之前的选中!!!(传的是单个值)

按照自己啊想要的来使用

 就酱紫啦!!!有甚么更好的方法及的告诉我呦!握爪

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值