• 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>
    复制代码

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

    复制代码
     1   methods: {
     2     leftClick(data, node, dom) {
     3       let event = window.event || arguments.callee.caller.arguments[0];
     4       var ctrlKeyDowned = event.ctrlKey;
     5       var shiftKeyDowned = event.shiftKey;
     6       // 走单击事件
     7 
     8       var allTreeNode = this.$refs.treeRef.getNode(1);
     9       this.clickTime = "";
    10       if (ctrlKeyDowned == false && shiftKeyDowned == false) { // 都没有点击
    11         this.cancelSelectTree(); // 取消原来的选中
    12         this.leftTreeSelectedArr.splice(0);
    13         this.leftTreeSelectedArr.push(data);
    14       } else if (ctrlKeyDowned == true && shiftKeyDowned == false) { // 只点击ctrl
    15         this.$set(data, "Selected", true);
    16         var isIN = this.leftTreeSelectedArr.every(item => {
    17           return item.id != data.id;
    18         });
    19         isIN && this.leftTreeSelectedArr.push(data);
    20         if (!isIN) {
    21           // 如果已经是选中的了,那么应该取消选择
    22           data.Selected = false;
    23           this.leftTreeSelectedArr.map((item, i) => {
    24             if (item.id == data.id) {
    25               this.leftTreeSelectedArr.splice(i, 1);
    26               this.$refs.treeRef.setCurrentKey(); // 取消高亮,要不然区分不出来,是不是没有选中
    27             }
    28           });
    29         }
    30       } else if (ctrlKeyDowned == false && shiftKeyDowned == true) { // 只点击shift
    31         this.delayeringArr.splice(0);
    32         this.delayering([allTreeNode]); // 把现在展开的数据都扁平化
    33         this.$set(data, "Selected", true);
    34         this.leftTreeSelectedArr.push(data);
    35         this.shiftTree(); // shifit多选
    36       }
    37     }
    38   }
    复制代码

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

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

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

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

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

    复制代码
     1 treeData: [
     2         {
     3           id: 1,
     4           name: "1节点",
     5           childrenId: [
     6             {
     7               id: 2,
     8               name: "2节点",
     9               childrenId: [
    10                 {
    11                   id: 5,
    12                   name: "5节点",
    13                   childrenId: []
    14                 },
    15                 {
    16                   id: 6,
    17                   name: "6节点",
    18                   childrenId: []
    19                 }
    20               ]
    21             },
    22             {
    23               id: 3,
    24               name: "3节点",
    25               childrenId: [
    26                 {
    27                   id: 7,
    28                   name: "7节点",
    29                   childrenId: []
    30                 }
    31               ]
    32             },
    33             {
    34               id: 4,
    35               name: "4节点",
    36               childrenId: [
    37                 {
    38                   id: 8,
    39                   name: "8节点",
    40                   childrenId: []
    41                 },
    42                 {
    43                   id: 9,
    44                   name: "9节点",
    45                   childrenId: []
    46                 },
    47                 {
    48                   id: 10,
    49                   name: "10节点",
    50                   childrenId: [
    51                     {
    52                       id: 11,
    53                       name: "11节点",
    54                       childrenId: []
    55                     },
    56                     {
    57                       id: 12,
    58                       name: "12节点",
    59                       childrenId: []
    60                     }
    61                   ]
    62                 }
    63               ]
    64             }
    65           ]
    66         }
    67       ]
    复制代码

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

     

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

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

    复制代码
     1     delayering(allTreeNode, pid) {
     2       allTreeNode.map(item => {
     3         this.delayeringArr.push({
     4           id: item.data.id,
     5           pid: pid ? pid : "null",
     6           name: item.data.name
     7         });
     8         if (
     9           item.hasOwnProperty("childNodes") &&
    10           item.childNodes.length &&
    11           item.expanded
    12         ) { // 通过检查有没有子节点,并且查看是否展开,从而确定是否递归
    13           this.delayering(item.childNodes, item.data.id);
    14         }
    15       });
    16     },
    复制代码

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

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

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

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

    复制代码
     1     shiftTree() {
     2       console.log("this.leftTreeSelectedArr", this.leftTreeSelectedArr);
     3       console.log("this.delayeringArr", this.delayeringArr);
     4       // 把第一个和最后一个当成是shift选择的
     5       var nodeLength = this.leftTreeSelectedArr.length;
     6       var startNode = this.leftTreeSelectedArr[0];
     7       var startNodeId = startNode.id;
     8       var endNode = this.leftTreeSelectedArr[nodeLength - 1];
     9       var endNodeId = endNode.id;
    10 
    11       // var startIndex = this.delayeringArr.filter((item,i)=>{
    12       //   return itemid == startNodeId;
    13       // })
    14       // var endIndex = this.delayeringArr.filter((item,i)=>{
    15       //   return itemid == endNodeId;
    16       // })
    17       var startIndex, endIndex;
    18       this.delayeringArr.map((item, i) => {
    19         if (item.id == startNodeId) {
    20           startIndex = i;
    21         }
    22         if (item.id == endNodeId) {
    23           endIndex = i;
    24         }
    25       });
    26       if (startIndex > endIndex) {
    27         var rongIdex = endIndex;
    28         endIndex = startIndex;
    29         startIndex = rongIdex;
    30       }
    31       console.log(startIndex, endIndex);
    32       this.leftTreeSelectedArr.splice(0);
    33       this.delayeringArr.map((item, i) => {
    34         if (i >= startIndex && i <= endIndex) {
    35           console.log("需要选中的name", item.name);
    36           var node = this.$refs.treeRef.getNode(item.id);
    37           this.$set(node.data, "Selected", true);
    38           this.leftTreeSelectedArr.push(node.data);
    39         }
    40       });
    41       console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
    42     }
    复制代码

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

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

      1 <template>
      2   <div id="MyVue">
      3     <el-tree
      4       ref="treeRef"
      5       :data="treeData"
      6       node-key="id"
      7       :props="defaultProps"
      8       @node-click="leftClick"
      9     >
     10        <span class="custom-tree-node" slot-scope="{ node, data }">
     11          <span :class="data.Selected?'sel':''">{{ node.label }}</span>
     12        </span>
     13     </el-tree>
     14     <div>扁平化数据:{{delayeringArr}}</div>
     15   </div>
     16 </template>
     17 <script>
     18 export default {
     19   name: "MyVue",
     20   data() {
     21     return {
     22       defaultProps: {
     23         children: "childrenId",
     24         label: "name"
     25       },
     26       treeData: [
     27         {
     28           id: 1,
     29           name: "1节点",
     30           childrenId: [
     31             {
     32               id: 2,
     33               name: "2节点",
     34               childrenId: [
     35                 {
     36                   id: 5,
     37                   name: "5节点",
     38                   childrenId: []
     39                 },
     40                 {
     41                   id: 6,
     42                   name: "6节点",
     43                   childrenId: []
     44                 }
     45               ]
     46             },
     47             {
     48               id: 3,
     49               name: "3节点",
     50               childrenId: [
     51                 {
     52                   id: 7,
     53                   name: "7节点",
     54                   childrenId: []
     55                 }
     56               ]
     57             },
     58             {
     59               id: 4,
     60               name: "4节点",
     61               childrenId: [
     62                 {
     63                   id: 8,
     64                   name: "8节点",
     65                   childrenId: []
     66                 },
     67                 {
     68                   id: 9,
     69                   name: "9节点",
     70                   childrenId: []
     71                 },
     72                 {
     73                   id: 10,
     74                   name: "10节点",
     75                   childrenId: [
     76                     {
     77                       id: 11,
     78                       name: "11节点",
     79                       childrenId: []
     80                     },
     81                     {
     82                       id: 12,
     83                       name: "12节点",
     84                       childrenId: []
     85                     }
     86                   ]
     87                 }
     88               ]
     89             }
     90           ]
     91         }
     92       ],
     93       delayeringArr: [], // 扁平化之后的数据
     94       leftTreeSelectedArr: [] // 选中的数据
     95     };
     96   },
     97   props: {},
     98   mounted() {},
     99   components: {},
    100   computed: {},
    101   methods: {
    102     leftClick(data, node, dom) {
    103       let event = window.event || arguments.callee.caller.arguments[0];
    104       var ctrlKeyDowned = event.ctrlKey;
    105       var shiftKeyDowned = event.shiftKey;
    106 
    107       var allTreeNode = this.$refs.treeRef.getNode(1);
    108       console.log("allTreeNode: ", allTreeNode);
    109       if (ctrlKeyDowned == false && shiftKeyDowned == false) {
    110         this.cancelSelectTree(); // 取消原来的选中
    111         this.leftTreeSelectedArr.splice(0);
    112         this.leftTreeSelectedArr.push(data);
    113       } else if (ctrlKeyDowned == true && shiftKeyDowned == false) {
    114         // this.leftTreeSelectedArr.splice(0);
    115         // data.Selected = true;
    116         this.$set(data, "Selected", true);
    117         var isIN = this.leftTreeSelectedArr.every(item => {
    118           return item.id != data.id;
    119         });
    120         isIN && this.leftTreeSelectedArr.push(data);
    121         console.log("isIN: ", isIN);
    122         if (!isIN) {
    123           // 如果已经是选中的了,那么应该取消选择
    124           data.Selected = false;
    125           this.leftTreeSelectedArr.map((item, i) => {
    126             if (item.id == data.id) {
    127               this.leftTreeSelectedArr.splice(i, 1);
    128               this.$refs.treeRef.setCurrentKey(); // 取消高亮,要不然区分不出来,是不是没有选中
    129             }
    130           });
    131         }
    132         console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
    133       } else if (ctrlKeyDowned == false && shiftKeyDowned == true) {
    134         this.delayeringArr.splice(0);
    135         this.delayering([allTreeNode]); // 把现在展开的数据都扁平化
    136         this.$set(data, "Selected", true);
    137         this.leftTreeSelectedArr.push(data);
    138         this.shiftTree(); // shifit多选
    139       }
    140     },
    141     // 把所有的数据,进行扁平化处理
    142     delayering(allTreeNode, pid) {
    143       allTreeNode.map(item => {
    144         this.delayeringArr.push({
    145           id: item.data.id,
    146           pid: pid ? pid : "null",
    147           name: item.data.name
    148         });
    149         if (
    150           item.hasOwnProperty("childNodes") &&
    151           item.childNodes.length &&
    152           item.expanded
    153         ) {
    154           // 通过检查有没有子节点,并且查看是否展开,从而确定是否递归
    155           this.delayering(item.childNodes, item.data.id);
    156         }
    157       });
    158     },
    159     shiftTree() {
    160       console.log("this.leftTreeSelectedArr", this.leftTreeSelectedArr);
    161       console.log("this.delayeringArr", this.delayeringArr);
    162       // 把第一个和最后一个当成是shift选择的
    163       var nodeLength = this.leftTreeSelectedArr.length;
    164       var startNode = this.leftTreeSelectedArr[0];
    165       var startNodeId = startNode.id;
    166       var endNode = this.leftTreeSelectedArr[nodeLength - 1];
    167       var endNodeId = endNode.id;
    168 
    169       // var startIndex = this.delayeringArr.filter((item,i)=>{
    170       //   return itemid == startNodeId;
    171       // })
    172       // var endIndex = this.delayeringArr.filter((item,i)=>{
    173       //   return itemid == endNodeId;
    174       // })
    175       var startIndex, endIndex;
    176       this.delayeringArr.map((item, i) => {
    177         if (item.id == startNodeId) {
    178           startIndex = i;
    179         }
    180         if (item.id == endNodeId) {
    181           endIndex = i;
    182         }
    183       });
    184       if (startIndex > endIndex) {
    185         var rongIdex = endIndex;
    186         endIndex = startIndex;
    187         startIndex = rongIdex;
    188       }
    189       console.log(startIndex, endIndex);
    190       this.leftTreeSelectedArr.splice(0);
    191       this.delayeringArr.map((item, i) => {
    192         if (i >= startIndex && i <= endIndex) {
    193           console.log("需要选中的name", item.name);
    194           var node = this.$refs.treeRef.getNode(item.id);
    195           this.$set(node.data, "Selected", true);
    196           this.leftTreeSelectedArr.push(node.data);
    197         }
    198       });
    199       console.log("this.leftTreeSelectedArr: ", this.leftTreeSelectedArr);
    200     }
    201   }
    202 };
    203 </script>
    204 <style lang="scss" scoped>
    205 #MyVue {
    206   width: 100%;
    207   height: 100%;
    208   user-select: none;
    209   .sel{
    210     color: aqua;
    211   }
    212 }
    213 </style>
    View Code

     

  • 相关阅读:
    MyBatis学习
    Redis实现Session持久化
    【等离子体】平均自由程和反应速率
    【mq】从零开始实现 mq-13-注册鉴权 auth
    [SWPUCTF 2021 新生赛]easy_sql - 联合注入||报错注入||sqlmap
    wpf datagrid 主从表关联查询
    CSS基础(10)- 常规流
    用于细胞定位的指数距离变换图--Exponential Distance Transform Maps for Cell Localization
    1.初识jQuery
    【Android】Android Studio 底部快捷按钮没了去哪找
  • 原文地址:https://www.cnblogs.com/daniao11417/p/16288289.html