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

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

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

 

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

<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多选的结果。请看下面的草图

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

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

Element中Tree树结构组件中实现Ctrl和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       ]

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

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

 

那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之后,就能把现在树结构中,已经展开的树结构,格式化成为一个一维的数组。请看下面的截图

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

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

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

 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组件)

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

  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

 

发表评论

相关文章