iview自定义下拉树菜单

最近由于项目需要,封装了第二种下拉树,带checkBox并且可以支持快速选择的下拉树。样式如下


自定义下拉树菜单.png

所实现交互功能如下:

1.点击对应的层级按钮,自动勾选出对应的所有同级节点。

2.点击自定义,清空所有勾选的节点。

3.勾选中不同层级的节点或同层级节点并没有全部选中,自动切换到自定义节点,并保存之前勾选的节点不清空。

4.在自定义中,若勾选的节点是同一个层级且此层级节点全部被选中,自动切换到对应层级按钮。

下面开始贴代码( 由于我将这种下拉树和之前普通的下拉树 是封装到同一个组件中的,所以只贴跟这次关联度较高的代码,之前的线性数组递归成树不再重复展示)

复制代码
<RadioGroup v-model="radioValue" v-if="showCheckBox" @on-change="selectedRadioHandle">
        <Radio
          style="margin-left: 10px"
          :label="item.value"
          v-for="item in radioArray"
          :key="item.value"
        >{{item.label}}</Radio>
</RadioGroup>
<Tree
        ref="tree"
        :data="suitableTreeData"
        @on-check-change="handleCheckedChange"
        check-strictly
        check-directly
        show-checkbox
        v-if="showCheckBox"
      ></Tree>
      <Button style="margin-left: 300px;" v-if="showCheckBox" @click="handleSubmit" type="primary" ghost>确定</Button>
      <Button v-if="showCheckBox" type="primary" ghost style="margin-left: 8px" @click="cancel">取消</Button>

首先讲解tree组件上面的参数:

1.check-strictly 在iview的api中是"在显示复选框的情况下,是否严格的遵循父子不互相关联的做法",简单的说就是父子节点不关联。

2.check-directly 在iview的api中是"开启后,在 show-checkbox 模式下,select 的交互也将转为 check"。

3.show-checkbox是支持多选。

接下来就是实现上面交互所需要的逻辑和代码

1.要实现第一个"点击对应的层级按钮,自动勾选出对应得所有同级节点"这个比较简单。将radioGroup里面的按钮value值根据节点层级设为对应的2,3,4,5,0。0代表自定义节点,用v-model双向绑定一个radioValue值,当点击radio按钮时将此变量作为参数传入一个找出所有同层级节点方法中。方法代码如下:

复制代码
 findLevelNode(tree, nodeLevel) {
      //找出某层级所有节点
      const _this = this;
      // console.log("nodeLevel",nodeLevel);
      tree.forEach(item => {
        if (item.level == nodeLevel) {
          _this.checkedNodeArr.push(item);
        } else {
          if (item.children) {
            _this.findLevelNode(item.children, nodeLevel);
          }else { return}
        }
      });
      _this.checkedNodeArr = _this.checkedNodeArr.filter(item => {
        //这里用filter是因为递归出来的数组中会存放上一次选择的所有节点,所以过滤出当前层级的节点
          if (item.level == nodeLevel) {return item}
        }
      );
      return _this.checkedNodeArr;
    },

2.实现第二个"点击自定义,清空所有勾选的节点"的交互也比较简单,也是用上面的方法,当选择自定义的时候,会返回一个空数组,所以不再赘述。

3.第三个需求中"勾选中不同层级的节点或同层级节点并没有全部选中,自动切换到自定义按钮,并保存之前勾选的节点不清空"。

这个交互分为两个步骤,第一个是"勾选中不同层级的节点或同层级节点并没有全部选中,自动切换到自定义节点"。要实现这个效果,首先要获取到所勾选的节点,并判断勾选的节点是否全部属于同一个层级,如果不是切换到自定义*( 获取勾选的节点可以用this.$refs.tree.getCheckedNodes()来实现 )* 。然后要判断当前选中层级的所有节点中有没有checked属性为false的*( 这里也是用上面的findLevelNode方法来实现 )*。上面两个判断我都是用ES6的every()方法来实现

复制代码
let checkedArr = _this.$refs.tree.getCheckedNodes();
      let isChecked = checkedArr.every(item => {
        //选中的checkBox的层级不一致切换到自定义
        return item.level == _this.radioValue;
      });
      let checkArr = _this.findLevelNode( _this.suitableTreeData,_this.radioValue);
      let isChecked2 = checkArr.every(item => {
        //如果有一个同层级级节点checked为false切换到自定义
        return item.checked == true;
      });
      if (!isChecked || !isChecked2) {
        _this.radioValue = "0";
        _this.checkedNodesId = checkedArr.map(i => {//保存自动切换自定义时所勾选节点的id
          return i.id;
        });
      }

由于之前设定的点击自定义按钮会清空所选节点,而要实现"切换到自定义按钮,并保存之前的勾选的节点不清空"这个逻辑,跟之前有点相冲突,所以比前两个交互难一点。这里需要在data里创建一个数组用来保存自动切换到自定义时所勾选的节点id,实现就是上面代码中checkedNodesId数组。然后在之前的getTree方法中添加一个判断

复制代码
          if (_this.radioValue == "0") {
            //解决勾选不同层级的复选框后,切换自定义按钮时,已勾选复选框取消选中的问题
            _this.checkedNodesId.forEach(d => {
              obj.id == d ? (obj.checked = true) : obj.checked;
            });
          } else {
            if (obj.level == _this.radioValue) {
              obj.checked = true;
            }
          }

这样在勾选不同层级或取消同层级的一个节点自动切回自定义时,也会保存上一次勾选的值。不过这样也造成了一个bug,那就时从其他radio按钮直接点回自定义按钮时,也会保存上一次的所选择的按钮,并没有清空。要解决这个bug就需在RadioGroup 的事件函数中添加一个判断,当value为0时,将checkedNodesId这个数组清空,就能解决。

4.实现"在自定义中,若勾选的节点是同一个层级且此层级节点全部被选中,自动切换到对应层级按钮。"要实现这个交互,首先也要获取所有勾选的节点( 也是用this.$refs.tree.getCheckedNodes()来实现 ),然后再将这些节点分级,我们可以将使用getCheckedNodes方法获取的节点打印出来看看

log.png

这里我分级采用的方法使用reduce将数组分级,代码如下:

复制代码
groupByArray(objArr, porperty) {
      //根据属性值将对象数组分类
      return objArr.reduce((acc, obj) => {
        let key = obj[porperty];
        if (!acc[key]) {
          acc[key] = [];
        }
        acc[key].push(obj);
        return acc;
      }, {});
    }

如果对reduce不太熟悉可以去mdn上看看。然后在Tree组件的on-check-change事件方法中调用,代码如下:

复制代码
handleCheckedChange() {
      const _this = this;
      let checkedArr = _this.$refs.tree.getCheckedNodes();
      let isChecked = checkedArr.every(item => {
        //选中的checkBox的层级不一致切换到自定义
        return item.level == _this.radioValue;
      });
      let checkArr = _this.findLevelNode( _this.suitableTreeData,_this.radioValue);
      let isChecked2 = checkArr.every(item => {
        //如果有一个同层级级节点checked为false切换到自定义
        return item.checked == true;
      });
      if (!isChecked || !isChecked2) {
        _this.radioValue = "0";
        _this.checkedNodesId = checkedArr.map(i => {
          return i.id;
        });
      }
   //上面是之前的对第三个交互的判断
  //******************************************************************************************************************
 
      let finalCheckedArr = _this.groupByArray(checkedArr, "level"); //分级后的数组
      let currentLevel = null; //当前勾选的层级
      //如果只勾选了一个层级的节点,判断这个层级的节点是否全部勾选,如果是切换到对应的业务组,如果不是切换到自定义
      if (Object.keys(finalCheckedArr).length < 2) {
        currentLevel = Object.keys(finalCheckedArr)[0];
        let currentLevelArr = _this.findLevelNode(_this.suitableTreeData, currentLevel).map(i => i.id);
        let currentCheckedLevelArr =  Object.values(finalCheckedArr)[0].map(i => i.id);
        //isEqual()是lodash的方法,用来判断对象或数组是否相等
        isEqual(currentCheckedLevelArr, currentLevelArr)? (_this.radioValue = currentLevel.toString()): _this.radioValue;
        }
      // console.log("finalCheckedArr", this.$ps(finalCheckedArr));
     // console.log("checkedArr", this.$ps(checkedArr));
    },

以上就是实现此种下拉树交互的主要代码
© 著作权归作者所有,转载或内容合作请联系作者

喜欢的朋友记得点赞、收藏、关注哦!!!

相关推荐
结冰架构11 分钟前
【AI提示词】马斯洛需求分析专家
大数据·人工智能·ai·需求分析·提示词
程序员buddha34 分钟前
用Maven定位和解决依赖冲突
java·maven
液态不合群39 分钟前
rust程序静态编译的两种方法总结
开发语言·后端·rust
努力的搬砖人.41 分钟前
maven如何搭建自己的私服(LINUX版)?
java·linux·maven
zfj3211 小时前
用java实现一个简单的sql select 解析器,无需第三方依赖,完全从0开始
java·sql
bingbingyihao1 小时前
SpringBoot教程(vuepress版)
java·spring boot·后端
喝养乐多长不高2 小时前
数据结构--红黑树
java·数据结构·算法·红黑树·二叉搜索树·avl树
CHANG_THE_WORLD2 小时前
Mac 平台获取地区标识符号
java·开发语言·macos
一切皆有迹可循2 小时前
Spring Boot 基于 CAS 实现单点登录:原理、实践与优化全解析
java·spring boot·后端
Clf丶忆笙2 小时前
Spring Boot配置文件详解:从入门到精通
java·spring boot