Element自身是有一个Transfer穿梭框组件的,这个组件是穿梭框结合checkbox复选框来实现的,功能比较单一,自己想实现这个功能也是很简单的,只是在项目开发中,项目排期紧,没有闲功夫来实现罢了,但这个组件只适合用来实现较为简单的左右数据添加删除的效果,复杂一点的树结构穿梭框就难实现多了,当然也有造好的轮子等你使用,这里推荐一个比较好用的穿梭树组件el-tree-transfer。
这个el-tree-transfer轮子好是好,但还是没有达到我的需求,确切的说是没有达到我们公司产品的需求,我们公司产品的需求在这里vue+element-ui之tree树形控件有关子节点和父节点之间的各种选中关系详解,尬笑脸... 其实之前实现我们产品的需求时我心里就已经一万个草泥马呼啸而过了,现在又要在这个基础上添加一个穿梭框的效果,阿西吧,我除了苦笑还能干啥?前端的同行们,我们遇到这样奇葩的需求,除了苦笑还能干啥?什么?你说怼回去?有用吗?怼回去的后果是除了别人说你爱牢骚情商低,你还能得到啥?什么?你说尥蹶子?你老婆答应了吗?你小孩答应了吗?你的房贷车贷答应了吗?消停地自己哭吧!这就是余欢水式的中年危机!!!
叽叽歪歪了这许多,还是赶紧看看如何实现吧,其实说白了就是把穿梭框左边树组件选中的数据复制一份给右边的树组件,这样在vue“数据驱动视图”的牛逼格拉斯思想下,右边树组件就会完美显示左边勾选的数据,然后再把左边已选中的数据给删除了就行了。说干就干,来啊,造作啊,反正有大把时光。
//往右侧添加数据的按钮
addRight(){
//this.checkedKeys保存的是每次勾选的数据以及上一次勾选的数据
this.leftCheckedKeys.push(...this.$refs.leftTree.getCheckedKeys());
this.leftCheckedKeys = [...new Set(this.leftCheckedKeys)];
this.rightData = this.setRightData(this.leftAllData, this.leftCheckedKeys);
this.leftDel(this.leftData, this.$refs.leftTree.getCheckedKeys());
this.$refs.leftTree.setCheckedKeys([]);
},
//设置右侧树-递归循环左侧数据并赋值给一个空数组而后返回该数组
setRightData(tree = [], keys = []){
let arr = [];
if (!!tree && tree.length !== 0) {
keys.forEach(i => {
tree.forEach(item => {
let obj = {};
if(i == item.id){
obj.id = item.id;
obj.label = item.label;
obj.children = this.setRightData(item.children, keys);
arr.push(obj);
}
});
})
}
return arr;
},
//删除选中的节点-如节点有子节点未被选中则该节点不被删除
leftDel(tree = [], keys = []){
if (!!tree && tree.length !== 0) {
keys.forEach((i, index) => {
tree.forEach((item, idx) => {
if(keys[index] == tree[idx].id){
this.leftDel(item.children, keys)
if(!tree[idx].children || tree[idx].children.length < 1){
tree.splice(idx, 1)
}
}
});
})
}
},
其实右侧选中的树组件数据再添加给左侧的树组件数据通过这个套路也是基本没有问题的,反正套路基本都一样,但问题是右侧选中的数据如何插入到左侧它本来该在的位置呢?通过这个套路还能实现吗?比如在左侧选中的一个子级元素连同它的父级和祖先级一起添加到了右侧,此时选中的数据组成的数组比如是[1,3,5],然后我又在左侧选中了一个子级元素连同它的父级和祖先级一起添加到了右侧,此时选中的数据组成的数组比如是[1,4,6],那么问题来了,我在右侧勾选了[1,4,6]这个数组数据构成的选中树,如何把它复原到左侧的树组件中呢?还是递归循环?那你怎么判断哪个是祖先元素呢?哪个是父元素呢?那个是子元素呢?比如你如何根据数组中的1把数组中的4组合成父子关系然后再赋值给左侧的树组件数据呢?如何又根据1,4来把6再组合成祖先、父级、子级的关系再赋值给左侧树组件的数据呢?况且左侧祖先级1的下边还可能有2这个子元素呢?而且有时,我们勾选的数据不一定就是按照从上往下来依次勾选的,可能是先勾选了下边的一个,然后又勾选了上边的一个,然后又勾选了一个其他的数据,然后又在这个的上边勾选了一个,比如我们如果按照从上往下的顺序来依次勾选,得到的数组可能是[1,3,5,7,9],但是由于这次我们不按照从上往下依次勾选,而是打乱了顺序,往数组中添加元素又基本是push进去的,所以这次得到的数据有可能就是[1,3,9,5,7],那这种情况又该如何把右侧勾选的数据再完美的添加到左侧呢?是不是有点晕了?其实一开始我也晕,但情况就是这么个情况,问题就是这么个问题,这种穿梭树组件跟element那个简单的基于checkbox的穿梭框不同,那个穿梭框不存在上下级的关系,直接往数组中push就OK了。
那么这个问题是不是就进入了死胡同实现不了你呢?当然不是,在看了el-tree-transfer这个轮子的原理后,如醍醐灌顶,是恍然大悟。其实一开始能想到我文中之前的那种实现方法也是很不错的,至少自己思考了,米兰.昆德拉说“人类一思考,上帝就发笑。” 这当然是句玩笑,思想很重要。
但是el-tree-transfer这个轮子的实现效果是基于父子关联的,但我们的实际需求是父子基本不关联,即选中了一个元素,若该元素有子元素,子元素就可以不选中,若该元素有父元素和祖先元素,它的父元素和祖先元素统统都要选中,这个功能我早前已经实现了,这里不再多说,有兴趣的可以移步vue+element-ui之tree树形控件有关子节点和父节点之间的各种选中关系详解。我的这个需求el-tree-transfer就玩不转了,但它玩不转不要紧,我还是领悟到了它的思想,在这里还是要感谢这个轮子的作者。这个轮子用到了element树组件的append方法,我咋就没有想到呢?而且作者的思想也确实牛逼,具体咋牛逼,一两句话说不清楚,直接上代码吧: