vue elementui 多选级联组件 全选功能

388 阅读1分钟

cascader组件

  <el-cascader
      ref="elCascaderRef"
      v-model="cascaderIds"
      :show-all-levels="false"
      :options="cascaderOptions"
      :props="{ multiple: true, ...fieldNames }"
      :collapse-tags="collapseTags"
      clearable filterable
      @change="onCascaderChange">
  </el-cascader>
</template>

<script>
// 缓存值 上一次选中值
let lastSelected = []
let dataLevel = 0  // 级联层级, 默认0层
export default {
  inheritAttrs: false,
  name: 'multiple-cascader',
  props: {
      // 选项
      options: {
          type: Array,
          default() {
              return [];
          }
      },
      // 已选中选项
      mulSelectedVal: {
          type: Array,
          default() {
              return [];
          }
      },
      collapseTags: {
          type: Boolean,
          default: true
      },
      // 自定义字段名
      fieldNames: {
          type: Object,
          default() {
              return {
                  label: 'name',
                  value: 'id',
              };
          }
      }
  },
  data() {
      return {
          cascaderIds: []
      };
  },
  computed: {
      // 级联列表
      cascaderOptions() {
          this.options.unshift({ children: null, id: '全选', name: '全选' })
          return this.options
      },

      // 全选值
      cascaderAllValue() {
          var model = []
          function tree2arr(arr, str, level) {
              dataLevel = (level + 1) // 实际数据结构是几层
              arr.forEach(it => {
                  let newStr = str.length ? [...str, it.id] : [it.id];
                  if (it.children) {
                      tree2arr(it.children, newStr, level + 1)
                  } else {
                      model.push(newStr)
                  }
              })
          }
          tree2arr(this.cascaderOptions, [], 0)
          return model
      },
  },
  methods: {
      onCascaderChange(node) {
          let current = [];   // 当前勾选项
          let isCheck = false  // 【勾选 | 反选】
          if(node.length >= lastSelected.length) {
              let keys = lastSelected.map(item => JSON.stringify(item))
              current = node.filter(item => !keys.includes(JSON.stringify(item)))
              isCheck = true
          }else {
              let keys = node.map(item => JSON.stringify(item))
              current = lastSelected.filter(item => !keys.includes(JSON.stringify(item)))
              isCheck = false
          }
          const currentValue = current.length > 0 ? current[0][0] || '' : ''
          
          if (currentValue === '全选') {
              if (isCheck) {
                  this.$set(this, 'cascaderIds', this.cascaderAllValue)
              } else {
                  this.$set(this, 'cascaderIds', [])
              }
          } else {
              // 除全选外
              let areaListAll = JSON.parse(JSON.stringify(this.cascaderAllValue))
              let firstValue = node.length > 0 ? node[0][0] || '' : ''
              if (firstValue !== '全选') { areaListAll.shift(); }
              
              if (node.length === areaListAll.length) {
                  this.$set(this, 'cascaderIds', [['全选'], ...this.cascaderIds])
              } else {
                  // 选中了全部,然后取消了某一个
                  if (firstValue === '全选') {
                      const ab = node.filter((item, index) => index >= 1)
                      this.$set(this, 'cascaderIds', ab)
                  }
              }
          }
          lastSelected = this.cascaderIds

          this.$nextTick(() => {
              let checkValue = this.$refs.elCascaderRef.getCheckedNodes() || []
              console.log('最深层级:', checkValue);
              // 更新绑定 筛选最后一层数据值
              this.$emit('update:mulSelectedVal', checkValue.filter(item => item.level === dataLevel).map(item => item.value));
              this.$emit('change', node)
          })
      },
  }
};
</script>

<style scoped lang="scss">
</style>

使用组件

    <my-cascader
      :mul-selected-val.sync="searchFormData.areaIds"
      :options="areaList"
    />
  </template>

  <script>
  import MyCascader from "./com.vue";
  export default {
    components: {
      MyCascader,
    },
    data() {
      return {
        searchFormData: {
          areaIds: [
            {
              name: "11",
              id: "11",
            },
          ],
        },
        areaList: [
          {
            name: "11",
            id: "11",
          },
          {
            name: "22",
            id: "22",
            children: [
              {
                name: "33",
                id: "33",
              }
            ]
          },
        ],
      };
    },

  };
  </script>