最近在vue项目上有个功能涉及到级联选择器的使用,溜达了一圈没有找到满足条件的…

要求:

  1. 标签选择必须时级联多选
  2. 根结点不能选,若根下有且只有一个叶子结点,则根可选
  3. 相同父级下只能存在一个叶子结点
  4. 父级多个兄弟是叶子结点时只能存在一个

溜达了一圈没有找到满足条件的,那就自己动手吧

解决思路:

  • 从ui组建入手
  • 从数据入手

因为项目采用的是element ui,又是用的vue框架,我选择了第二种,话不多说,上代码:

template

 <el-cascader ref="cascader"
                             @change="changeLabel"
                             :show-all-level="false"
                             :options="options"
                             :props="OptionsProps"
                             v-model="labelData"
                             separator=">>"
                             class="tag_option">
                </el-cascader>

methods代码:

 changeLabel(array) {
        let v = this;
        /**
         * 获取当前的点击结点
         * layering 当前的长度
         * layered  上次的长度
         * nodesList object 当前的结点数据
         *shareScopeEnd  array 上一次选中的
         * contentTags  array  当前所有的
         * */
        let selectData = array
        let nodesList = v.$refs.cascader.getCheckedNodes()[0]
        let layered=v.selectedData.length
        let layering=selectData.length
        let len=layering-layered>1
        //当前没有选中的标签
        if (this.selectedData.length == 0) {
          //是否存在子结点
          if (nodesList.children.length > 0) {
            this.formObj.selectData = []
            return
          } else {
            this.selectData = selectData
          }
          this.selectedData = selectData
        } else {
          // 是否存在子结点
          if (nodesList.parent === null) {
             v.lookChildren(nodesList,selectData,len)
            return;
          }
          //是否触发了多选
          if(len){
            v.refreshLabel()
            return;
          }
          v.FilterLabel(selectData)
        }
      },
   lookChildren(nodesList,selectData,len) {
        let v = this;
        //首次选择根结点
        if(nodesList.children.length<1) {
          v.refreshLabel()
        }else {
          //选择某个父亲结点的最后一个叶子结点
          if(len){
            v.refreshLabel()
          }else {
            v.findLayer(nodesList,selectData)
          }

        }
      },

Alt

    findLayer(nodesList,selectData,len){
        let v=this;
        nodesList.children.forEach(value => {
          //选择除根结点以外其他含有子结点的结点
            if (value.children.length > 1) {
              if(len){
                v.refreshLabel()
              }else {
                v.findLayer(value,selectData)
              }
            } else {
              if(isMoreSelect){
                v.refreshLabel()
              }else {
                v.FilterLabel(selectData)
              }
            }
        })
      }

Alt

/**
       * 过滤替换
       * 当前选中的结点替换父结点相同数据的老结点
       * */
      FilterLabel(selectData){
        let v=this;
        let tempList=[]
        selectData.map(value => {
          let v1 = value[0]
          let v2 = value[value.length - 2]
          v.selectedData.forEach(item => {
            if (item.length >= value.length) {
              let vv1 = item[0]
              let vv2 = item[item.length - 2]
              if (v1 === vv1 && v2 === vv2) {
                if (value.toString() !== item.toString()) {
                  //存放老的
                  tempList.push(item)
                }
              }
            }
          })
        })
        //过滤掉tempList中的数据
        v.$nextTick(()=>{
          let newList = selectData.filter(data => !tempList.some((ele) => ele.toString() === data.toString()))
          v.selectData = newList
          v.selectedData = newList
        })
      }

完成

在这里插入图片描述

方式2也可以采用图谱方式实现,时间紧就没有去尝试了

第一种也捯饬过,有点麻烦,就放弃了,最终也能达到需求了
感觉这种功能还是有需求的,希望能帮助到猿友们

若有不妥之处或是更好的方式,恭请上楼

Logo

前往低代码交流专区

更多推荐