Element中Tree树结构组件中实现Ctrl和Shift多选

        在Element中的树结构中, 实现多选功能,首先的是判断有没有按下键盘ctrl和shift按键。但是在Element中的tree组件的左键点击事件是没有提供$event鼠标属性判断的。所以就需要在函数中使用自身的$event来判断。请看树结构下面左键和右键点击的函数传参的截图。

  所以,左键的点击函数,需要自行判断。如下代码示例

<el-tree
     class="filter-tree"
     :load="loadNode"
     lazy
     :props="defaultProps"
     :filter-node-method="filterNode"
     :render-content="renderContent"
     ref="treeRef"
     :expand-on-click-node="false"
     @node-contextmenu="rightClick"
     @node-click="leftClick" // 左键点击事件
     :highlight-current="true"
     node-key="id"
     :check-on-click-node="true"
     :show-checkbox="false"
     check-strictly
></el-tree>

 里面的左键函数,是这样的

methods: {
    leftClick(data, node, dom) {
      let event = window.event || arguments.callee.caller.arguments[0];
      var ctrlKeyDowned = event.ctrlKey;
      var shiftKeyDowned = event.shiftKey;
      // 走单击事件

      var allTreeNode = this.$refs.treeRef.getNode(1);
      this.clickTime = "";
      if (ctrlKeyDowned == false && shiftKeyDowned == false) { // 都没有点击
        this.cancelSelectTree(); // 取消原来的选中
        this.leftTreeSelectedArr.splice(0);
        this.leftTreeSelectedArr.push(data);
      } else if (ctrlKeyDowned == true && shiftKeyDowned == false) { // 只点击ctrl
        this.$set(data, "Selected", true);
        var isIN = this.leftTreeSelectedArr.every(item => {
          return item.id != data.id;
        });
        isIN && this.leftTreeSelectedArr.push(data);
        if (!isIN) {
          // 如果已经是选中的了,那么应该取消选择
          data.Selected = false;
          this.leftTreeSelectedArr.map((item, i) => {
            if (item.id == data.id) {
              this.leftTreeSelectedArr.splice(i, 1);
              this.$refs.treeRef.setCurrentKey(); // 取消高亮,要不然区分不出来,是不是没有选中
            }
          });
        }
      } else if (ctrlKeyDowned == false && shiftKeyDowned == true) { // 只点击shift
        this.delayeringArr.splice(0);
        this.delayering([allTreeNode]); // 把现在展开的数据都扁平化
        this.$set(data, "Selected", true);
        this.leftTreeSelectedArr.push(data);
        this.shiftTree(); // shifit多选
      }
    }
  }

通过,第三行中的内容,获取到鼠标的点击事件属性,然后从中获取到是都点击了键盘的Ctrl和Shift;

  Ctrl多选就不用过多的介绍了,把点击树结构的内容, 通过去重判断,直接放在leftTreeSelectedArr中就可以了。这里就不做过多的介绍了。具体请看,14至30行代码。下面主要是讲解一下,shift多选。

  Shfit多选,在平常的列表中是很好实现的。我们可以把所有的数据,放在一个一维的数组中,那么任意选择其中的两项的话,就能把数组分割成为三部分。其中的中间部分,也就是第二部分就是Shift多选的结果。请看下面的草图

 但是对于树结构的话,就稍微的麻烦一点了,树结构的数据是这样的。

那么他的真实的数据格式应该是这样的。

treeData: [
        {
          id: 1,
          name: "1节点",
          childrenId: [
            {
              id: 2,
              name: "2节点",
              childrenId: [
                {
                  id: 5,
                  name: "5节点",
                  childrenId: []
                },
                {
                  id: 6,
                  name: "6节点",
                  childrenId: []
                }
              ]
            },
            {
              id: 3,
              name: "3节点",
              childrenId: [
                {
                  id: 7,
                  name: "7节点",
                  childrenId: []
                }
              ]
            },
            {
              id: 4,
              name: "4节点",
              childrenId: [
                {
                  id: 8,
                  name: "8节点",
                  childrenId: []
                },
                {
                  id: 9,
                  name: "9节点",
                  childrenId: []
                },
                {
                  id: 10,
                  name: "10节点",
                  childrenId: [
                    {
                      id: 11,
                      name: "11节点",
                      childrenId: []
                    },
                    {
                      id: 12,
                      name: "12节点",
                      childrenId: []
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]

 那么树结构在页面上渲染完成之后就是这样的:

那shift多选是怎么判断的呢,怎么知道这个层级是属于哪个呢,怎么知道这个层级下面的内容需不需选中呢,如果展开了,就是应该选中的,如果没有展开是不是就不需要选中呢。所以的这些问题,如果思考下来的话, 确实比较复杂,如果遍历的话,也是很难的。任意选中两个之后,都不知道应该是向上查找遍历,还是向下查找遍历。所以遍历的话,是不可用的,或者说是不太容易实现的。

  回到问题的本质,在一维的数组,shif多选是很简单的。那么这个树形结构是不是也可以转换成一维的呢。按照这个思路,我们通过递归循环遍历,把这个数组转换成为一维的数组。请看下面的代码

delayering(allTreeNode, pid) {
      allTreeNode.map(item => {
        this.delayeringArr.push({
          id: item.data.id,
          pid: pid ? pid : "null",
          name: item.data.name
        });
        if (
          item.hasOwnProperty("childNodes") &&
          item.childNodes.length &&
          item.expanded
        ) { // 通过检查有没有子节点,并且查看是否展开,从而确定是否递归
          this.delayering(item.childNodes, item.data.id);
        }
      });
    },

 调用的时候,则需要把所有的节点的数据都传过去。

this.delayeringArr.splice(0);
this.delayering([allTreeNode]); // 把现在展开的数据都扁平化

  调用delayering之后,就能把现在树结构中,已经展开的树结构,格式化成为一个一维的数组。请看下面的截图

 

当我们把树结构中的数据格式化成为一个一维的数组之后,我们就能判断了。那些是需要选中的。

shiftTree() {
      console.log("this.leftTreeSelectedArr", this.leftTreeSelectedArr);
      console.log("this.delayeringArr", this.delayeringArr);
      // 把第一个和最后一个当成是shift选择的
      var nodeLength = this.leftTreeSelectedArr.length;
      var startNode = this.leftTreeSelectedArr[0];
      var startNodeId = startNode.id;
      var endNode = this.leftTreeSelectedArr[nodeLength - 1];
      var endNodeId = endNode.id;

      // var startIndex = this.delayeringArr.filter((item,i)=>{
      //   return itemid == startNodeId;
      // })
      // var endIndex = this.delayeringArr.filter((item,i)=>{
      //   return itemid == endNodeId;
      // })
      var startIndex, endIndex;
      this.delayeringArr.map((item, i) => {
        if (item.id == startNodeId) {
          startIndex = i;
        }
        if (item.id == endNodeId) {
          endIndex = i;
        }
      });
      if (startIndex > endIndex) {
        var rongIdex = endIndex;
        endIndex = startIndex;
        startIndex = rongIdex;
      }
      console.log(startIndex, endIndex);
      this.leftTreeSelectedArr.splice(0);
      this.delayeringArr.map((item, i) => {
        if (i >= startIndex && i <= endIndex) {
          console.log("需要选中的name", item.name);
          var node = this.$refs.treeRef.getNode(item.id);
          this.$set(node.data, "Selected", true);
          this.leftTreeSelectedArr.push(node.data);
        }
      });
      console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
    }

 

这个函数的主要目的就是,通过循环,找到对应的数据在扁平化处理之后数组数据中的位置。然后同理,就能找到需要选中的数据,通过设置Selected为true,则可以知道需要选中的节点。

  最后附上完成的代码, 包括其中的打印信息。(注意其中依赖Element的tree组件)

<template>
  <div id="MyVue">
    <el-tree
      ref="treeRef"
      :data="treeData"
      node-key="id"
      :props="defaultProps"
      @node-click="leftClick"
    >
       <span class="custom-tree-node" slot-scope="{ node, data }">
         <span :class="data.Selected?'sel':''">{{ node.label }}</span>
       </span>
    </el-tree>
    <div>扁平化数据:{{delayeringArr}}</div>
  </div>
</template>
<script>
export default {
  name: "MyVue",
  data() {
    return {
      defaultProps: {
        children: "childrenId",
        label: "name"
      },
      treeData: [
        {
          id: 1,
          name: "1节点",
          childrenId: [
            {
              id: 2,
              name: "2节点",
              childrenId: [
                {
                  id: 5,
                  name: "5节点",
                  childrenId: []
                },
                {
                  id: 6,
                  name: "6节点",
                  childrenId: []
                }
              ]
            },
            {
              id: 3,
              name: "3节点",
              childrenId: [
                {
                  id: 7,
                  name: "7节点",
                  childrenId: []
                }
              ]
            },
            {
              id: 4,
              name: "4节点",
              childrenId: [
                {
                  id: 8,
                  name: "8节点",
                  childrenId: []
                },
                {
                  id: 9,
                  name: "9节点",
                  childrenId: []
                },
                {
                  id: 10,
                  name: "10节点",
                  childrenId: [
                    {
                      id: 11,
                      name: "11节点",
                      childrenId: []
                    },
                    {
                      id: 12,
                      name: "12节点",
                      childrenId: []
                    }
                  ]
                }
              ]
            }
          ]
        }
      ],
      delayeringArr: [], // 扁平化之后的数据
      leftTreeSelectedArr: [] // 选中的数据
    };
  },
  props: {},
  mounted() {},
  components: {},
  computed: {},
  methods: {
    leftClick(data, node, dom) {
      let event = window.event || arguments.callee.caller.arguments[0];
      var ctrlKeyDowned = event.ctrlKey;
      var shiftKeyDowned = event.shiftKey;

      var allTreeNode = this.$refs.treeRef.getNode(1);
      console.log("allTreeNode: ", allTreeNode);
      if (ctrlKeyDowned == false && shiftKeyDowned == false) {
        this.cancelSelectTree(); // 取消原来的选中
        this.leftTreeSelectedArr.splice(0);
        this.leftTreeSelectedArr.push(data);
      } else if (ctrlKeyDowned == true && shiftKeyDowned == false) {
        // this.leftTreeSelectedArr.splice(0);
        // data.Selected = true;
        this.$set(data, "Selected", true);
        var isIN = this.leftTreeSelectedArr.every(item => {
          return item.id != data.id;
        });
        isIN && this.leftTreeSelectedArr.push(data);
        console.log("isIN: ", isIN);
        if (!isIN) {
          // 如果已经是选中的了,那么应该取消选择
          data.Selected = false;
          this.leftTreeSelectedArr.map((item, i) => {
            if (item.id == data.id) {
              this.leftTreeSelectedArr.splice(i, 1);
              this.$refs.treeRef.setCurrentKey(); // 取消高亮,要不然区分不出来,是不是没有选中
            }
          });
        }
        console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
      } else if (ctrlKeyDowned == false && shiftKeyDowned == true) {
        this.delayeringArr.splice(0);
        this.delayering([allTreeNode]); // 把现在展开的数据都扁平化
        this.$set(data, "Selected", true);
        this.leftTreeSelectedArr.push(data);
        this.shiftTree(); // shifit多选
      }
    },
    // 把所有的数据,进行扁平化处理
    delayering(allTreeNode, pid) {
      allTreeNode.map(item => {
        this.delayeringArr.push({
          id: item.data.id,
          pid: pid ? pid : "null",
          name: item.data.name
        });
        if (
          item.hasOwnProperty("childNodes") &&
          item.childNodes.length &&
          item.expanded
        ) {
          // 通过检查有没有子节点,并且查看是否展开,从而确定是否递归
          this.delayering(item.childNodes, item.data.id);
        }
      });
    },
    shiftTree() {
      console.log("this.leftTreeSelectedArr", this.leftTreeSelectedArr);
      console.log("this.delayeringArr", this.delayeringArr);
      // 把第一个和最后一个当成是shift选择的
      var nodeLength = this.leftTreeSelectedArr.length;
      var startNode = this.leftTreeSelectedArr[0];
      var startNodeId = startNode.id;
      var endNode = this.leftTreeSelectedArr[nodeLength - 1];
      var endNodeId = endNode.id;

      // var startIndex = this.delayeringArr.filter((item,i)=>{
      //   return itemid == startNodeId;
      // })
      // var endIndex = this.delayeringArr.filter((item,i)=>{
      //   return itemid == endNodeId;
      // })
      var startIndex, endIndex;
      this.delayeringArr.map((item, i) => {
        if (item.id == startNodeId) {
          startIndex = i;
        }
        if (item.id == endNodeId) {
          endIndex = i;
        }
      });
      if (startIndex > endIndex) {
        var rongIdex = endIndex;
        endIndex = startIndex;
        startIndex = rongIdex;
      }
      console.log(startIndex, endIndex);
      this.leftTreeSelectedArr.splice(0);
      this.delayeringArr.map((item, i) => {
        if (i >= startIndex && i <= endIndex) {
          console.log("需要选中的name", item.name);
          var node = this.$refs.treeRef.getNode(item.id);
          this.$set(node.data, "Selected", true);
          this.leftTreeSelectedArr.push(node.data);
        }
      });
      console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
    }
  }
};
</script>
<style lang="scss" scoped>
#MyVue {
  width: 100%;
  height: 100%;
  user-select: none;
  .sel{
    color: aqua;
  }
}
</style>

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
您好!要在Vue使用Element UI的Tree组件并实现懒加载,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了Vue和Element UI,并在您的项目引入它们。 2. 在需要使用Tree组件的Vue文件,先引入Tree组件和相关的样式: ```javascript import { Tree } from 'element-ui'; import 'element-ui/lib/theme-chalk/tree.css'; ``` 3. 在Vue组件注册Tree组件: ```javascript export default { components: { 'el-tree': Tree }, // ... } ``` 4. 在模板使用Tree组件,并设置相关属性和事件: ```html <template> <div> <el-tree :data="treeData" :load="lazyLoad" :lazy="true" :expand-on-click-node="false" @node-click="handleNodeClick" ></el-tree> </div> </template> ``` 在上面的代码,我们通过`:data`属性将的数据传递给Tree组件。`:load`属性用于指定懒加载函数,`:lazy`属性设置为`true`以启用懒加载功能,而`:expand-on-click-node`属性设置为`false`以禁用节点点击展开功能。同时,我们还可以通过`@node-click`事件处理节点的点击操作。 5. 在Vue组件的方法定义懒加载函数和节点点击事件处理方法: ```javascript export default { // ... methods: { lazyLoad(node, resolve) { // 模拟异步请求 setTimeout(() => { const children = [ { id: 1, label: '节点1' }, { id: 2, label: '节点2' }, { id: 3, label: '节点3' } ]; resolve(children); }, 1000); }, handleNodeClick(node) { console.log('点击了节点:', node); } } } ``` 在上面的代码,`lazyLoad`方法模拟了一个异步请求,通过`resolve`函数将加载到的子节点数据传递给Tree组件。`handleNodeClick`方法用于处理节点的点击事件,您可以根据需要进行相应的处理。 这样,您就可以在Vue使用Element UI的Tree组件并实现懒加载了。请注意,上述代码的数据和延时仅作为示例,您可以根据实际需求进行调整。希望对您有所帮助!如果您还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值