elementUI级联选择器(Cascader)组件->父关联子级->子级不关联父

2,260 阅读1分钟

需求如下:

项目开发中收到需求,需要用级联结构展示,选中父级的时候子级全部勾选,且显示的是勾选中的所有值;如果只勾选子级,父不关联在内;如果勾选了所有的子节点,且父节点不选中。实现的效果如下:

选择父级的时候全选 image.png

选择子级的时候不关联父级 image.png

1.自行封装组件 创建 NewCascader.vue

<template>
  <div>
    <el-cascader ref="myCascader" :options="options" v-model="vop" :show-all-levels="false"   
        @change="handleChange" 
        :props="{children: 'children',label: 'title', value:'id', multiple: true, 
            checkStrictly: true, emitPath: false, expandTrigger:'click'}" clearable>
    </el-cascader>
  </div>
  
 // :props(children:"更新为子级数组",label:"更新为数组名称",value:"更新为需要给后台传的值")其它参数请自行查阅ELement ui 文档
 
</template>
<script>
  export default {
    props: {
      // 级联树数据定义
      options: {
        type: Array,
        required: false,
        default: false
      },
      // 级联选择器一开始绑定值,需回显
      updateValue: {
        type: Array,
        required: false,
        default: false
      }
    },
    data() {
      return {
        // 选中的值
        vop: [],
        // 临时存放的当前选中值,用于后期的点击对比,获得当前节点值
        tmpVop: [],
        // 临时存放的值,用于递归函数给选中值
        tmp: '',
      }
    },
    watch: {
      /** v-model绑定得值 */
      vop: {
        handler(n) {
          // 如果数据发生变化
          if (n) {
            this.$emit('childByValue', this.vop)
          }
        },
        deep: true,
        immediate: true
      },
      /**  如果一开始就给级联选择器赋值了 */
      updateValue: {
        handler(n) {
          if (n) {
            // 拿到父级节点的值,进行回显
            this.vop = this.updateValue
            this.tmpVop = this.vop
          }
        },
        deep: true,
        immediate: true
      }
    },
    methods: {
      // 选中或取消选中后的赋值
      checkArr(value, options, operation) {
        options.map((x) => {
          if (value === x.id) {
            // 选中value项,并循环该节点下的其他所有子节点选中
            if (x.children) {
              this.checkArrNull(x.children, operation)
            }
          } else if (x.children) {
            this.checkArr(value, x.children, operation)
          }
        })
      },
      checkArrNull(options, operation) {
        options.map((x) => {
          // 如果有子项,则递归,没有则选中
          // 选中当前节点2判断子节点,有则继续递归
          if (operation === 'add') {
            this.tmp = this.tmp + ',' + x.id
          } else if (operation === 'sub') {
            this.tmp = this.tmp.split(',')
            // shanchu zhi
            this.tmp = this.removeValue(x.id, this.tmp)
            this.tmp = this.tmp.join(',')
          }
          if (x.children) {
            this.checkArrNull(x.children, operation)
          }
        })
      },
      // 获得点击change事件时点击节点的值
      valueChange(tmp1, tmp2) {
        for (var i = 0; i < tmp2.length; i++) {
          var obj = tmp2[i]
          var isExist = false
          for (var j = 0; j < tmp1.length; j++) {
            var aj = tmp1[j]
            if (obj === aj) {
              isExist = true
              break
            }
          }
          if (!isExist) {
            return obj
          }
        }
      },
      // 删除数组指定的值的元素
      removeValue(v, arr) {
        let index = arr.indexOf(v)
        if (index !== -1) {
          arr.splice(index, 1)
        }
        return arr
      },
      // 数组去重
      unique(arr) {
        var arr2 = arr.sort()
        var res = [arr2[0]]
        for (var i = 1; i < arr2.length; i++) {
          if (arr2[i] !== res[res.length - 1]) {
            res.push(arr2[i])
          }
        }
        return res
      },
      // 将options的value值按照value生成一组数组
      optionsToarr(options) {
        this.tmp = ''
        options.map((x) => {
          this.tmp = this.tmp + x.id + ','
          if (x.children) {
            this.optionsToarrChild(x.children)
          }
        })
      },
      optionsToarrChild(options) {
        options.map((x) => {
          this.tmp = this.tmp + x.id + ','
          if (x.children) {
            this.optionsToarrChild(x.children)
          }
        })
      },
      // change事件
      handleChange(value) {
        // 获得点击变化时的值,然后判断是加值还是减值。根据值去递归
        let valueCh = ''
        // 操作是选中还是取消
        let action = ''
        // 对比获得是选中还是取消操作
        if ((this.vop).length > 0) {
          if ((this.tmpVop).length > (this.vop).length) {
            valueCh = this.valueChange(this.vop, this.tmpVop)
            action = 'sub'
          } else {
            valueCh = this.valueChange(this.tmpVop, this.vop)
            action = 'add'
          }
        }
        if (valueCh) {
          this.tmp = this.vop.join(',')
          this.checkArr(valueCh, this.options, action)
          // 去重
          this.vop = this.unique(this.tmp.split(','))
        }
        // 获得options的value值一维数组,用于排序对照
        this.optionsToarr(this.options)
        if (this.tmp.substring(this.tmp.length - 1) === ',') {
          this.tmp = this.tmp.substring(0, this.tmp.length - 1)
        }
        this.tmp = this.tmp.split(',')
        // 排序
        this.vop.sort((prev, next) => {
          return this.tmp.indexOf(prev) - this.tmp.indexOf(next)
        })
        this.tmpVop = this.vop
      }
    },
    created() {
      // 创建时默认给tmpVop赋值
      this.tmpVop = this.vop
    }
  }

</script>

2.页面调用

  import NewCascader from '../components/NewCascader'
    components: {
      NewCascader
    },
    
     <NewCascader v-model="updateCheckerForm.dept" :updateValue="updateCheckerForm.dept"
         v-on:childByValue="childByValueUpdate" :options="departmentList" >
     </NewCascader>
     
      /** 修改时候级联选择子传值给父 */
      childByValueUpdate(childValue) {
        this.updateCheckerForm.dept = childValue
        console.log(this.updateCheckerForm.dept, 'this.updateCheckerForm.dept');
      },  
      

自定义数据

data () {
  return {
    dataList:[{
      id: 'zhinan',
      deptname: '指南',
      children: [{
        id: 'shejiyuanze',
        deptname: '设计原则',
        checked: true,
        children: [{
          id: 'yizhi',
          deptname: '一致'
        }, {
          id: 'fankui',
          deptname: '反馈'
        }, {
          id: 'xiaolv',
          deptname: '效率'
        }, {
          id: 'kekong',
          deptname: '可控'
        }]
      }, {
        id: 'daohang',
        deptname: '导航',
        children: [{
          id: 'cexiangdaohang',
          deptname: '侧向导航'
        }, {
          id: 'dingbudaohang',
          deptname: '顶部导航'
        }]
      }]
    }, {
      id: 'zujian',
      deptname: '组件',
      children: [{
        id: 'basic',
        deptname: 'Basic',
        children: [{
          id: 'layout',
          deptname: 'Layout 布局'
        }, {
          id: 'color',
          deptname: 'Color 色彩'
        }, {
          id: 'typography',
          deptname: 'Typography 字体'
        }, {
          id: 'icon',
          deptname: 'Icon 图标'
        }, {
          id: 'button',
          deptname: 'Button 按钮'
        }]
      }
    }],
      checkerForm: {
        dept:[],
      },
      updateCheckerForm:{
        account:[]
      },
    }
  }
},

至此就实现了级联选择组件(父关联子->子不关联父)