elementui+select实现全选

1,038 阅读2分钟

 实现下拉选择器支持全选

运行效果

输入2后,模糊查询后,点击全选,选中的是当前筛选后的全部,并不是实际所有下拉选项的全部

此修改时所处情况:当时该系统已经处于迭代更新状态,需求要求将所有多选的下拉选择器都改成支持 模糊查询 全选(是根据模糊查询后 现有匹配项的当前全选) 反选 有编码的还有支持输入编码可以自动匹配选中功能;功能不复杂但是涉及页面很多,所以在能够兼容全局页面的情况下编写了一下代码。

封装组件

components/selectCheckBox/index.vue

template部分

// template部分
  <el-select
    v-if="filterableFlag === 'filterable'"
    v-model="selectValue"
    :placeholder="placeholder"
    popper-class="smallSelectDropdown pop_select_down"
    :class="[defaultClass !== 'no' ? 'selectCheckBox' : '', className]"
    :style="style"
    multiple
    clearable
    collapse-tags
    filterable
    reserve-keyword
    :filter-method="filterableHandler"
    @visible-change="selectVisibleChange"
    @change="(v) => selectChange(v, showAll ? options : notAllOptions)"
  >
    <el-checkbox
      v-model="isSelectAll"
      :indeterminate="isIndeterminate"
      class="selectbox"
      style="padding-left:18px"
      @change="selectAllnotAllOptions"
      >全选</el-checkbox
    >
    <el-option
      v-for="item in showAll ? options : notAllOptions"
      :key="item[opv] + '0' + Math.random()"
      :label="item[opl]"
      :value="item[opv]"
    >
      <span class="check" />
      <span>{{ item[opl] }}</span>
    </el-option>
  </el-select>

props从外部接收的参数

  props: {
    // 父组件的样式名称
    defaultClass: {
      type: String,
      default: ''
    },
    // 产品名称等支持根据编码自动选中的 不需要传该属性
    // 其他需要传 filterableFlag === 'filterable'
    filterableFlag: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: ''
    },
    // 也是央视名称(因为是多人协作定义时候出现了冲突 导致同功能变量定义重复)
    className: {
      type: String,
      default: ''
    },
    // 因为是兼容的全局 有的页面是单独写的是style
    style: {
      type: Object,
      default: () => {}
    },
    //  下拉选择器的 备选项
    options: {
      type: Array,
      default: () => []
    },
    //  对应的el-options的value绑定的字段
    opv: {
      type: String,
      default: 'id'
    },
    // label绑定的字段
    opl: {
      type: String,
      default: 'label'
    },
    // 父组件传参过来的下拉备选项的初始数据(options用于子组件绑定)
    optionsOri: {
      type: Array,
      default: () => []
    },
    //  父组件原来选择器选中的的绑定值 其实和子组件的v-model保持一致
    modelOri: {
      type: Array,
      default: () => []
    }
  },

data watch  methods部分

mounted(离开页面后再返回保留原来的查询条件)

  data() {
    return {
      selectValue: [], // 当前子组件 v-model值
      isSelectAll: false, // 全选
      isIndeterminate: false, // 
      notAllOptions: [], // 模糊查询后产生的新数据
      showAll: true // 模糊查询后 是否显示全部备选项 默认为true
    };
  },
  watch: {
    isSelectAll: {
      handler(val) {
        this.$emit('selectChange', this.selectValue);
      }
    }
  },
  mounted() {
    if (this.modelOri.length > 0) {
      this.selectValue = this.modelOri;
      this.selectCheck(this.selectValue, this.options);
    }
  },
  methods: {
    // 根据模糊查询结果 全选
    selectAllnotAllOptions(v) {
      let opArr = this.showAll ? this.options : this.notAllOptions;
      this.selectValue = v ? opArr.map((item) => item[this.opv]) : [];
      this.isIndeterminate = false;
    },
    // filterableFlag === 'filterable' 自定义模糊查询
    filterableHandler(value) {
      if (value) {
        this.showAll = false;
        this.notAllOptions = [];
        this.notAllOptions = this.optionsOri.filter((item) => {
          return (
            item[this.opv].indexOf(value) > -1 ||
            item[this.opl].indexOf(value) > -1
          );
        });
      } else {
        this.showAll = true;
      }
      this.selectCheck(
        this.selectValue,
        this.showAll ? this.options : this.notAllOptions
      );
    },
    // visible-change事件
    selectVisibleChange(v) {
      if (v === false) {
        this.options = this.optionsOri;
        this.showAll = true;
      }
      this.$emit('selectVisibleChange', v);
      this.selectCheck(
        this.selectValue,
        this.showAll ? this.options : this.notAllOptions
      );
    },
    // change事件
    selectChange(v, arr) {
      this.$emit('selectChange', v);
      // 选中 对应的复选框更改状态,全选根据当前更改状态
      this.selectCheck(v, arr);
    },
    // 根据选中数据 更新全选框状态
    selectCheck(v, arr) {
      if (arr.length !== 0) {
        if (v && v.length === arr.length) {
          this.selectValue = arr.map((item) => item[this.opv]);
          this.isSelectAll = true;
        } else {
          this.isSelectAll = false;
        }
        this.isIndeterminate = v.length > 0 && v.length < arr.length;
      }
    }
}

样式补充

<style lang="scss">
.selectCheckBox .el-tag:first-child {
  max-width: calc(100% - 72px);
  .el-select__tags-text {
    display: inline-block;
    width: calc(100% - 18px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .el-icon-close {
    top: -7px;
  }
}
</style>
<style lang="scss">
.pop_select_down.is-multiple .el-select-dropdown__item {
  padding: 0 18px;
}
.pop_select_down.is-multiple .el-select-dropdown__list {
  padding-top: 0;
}
.pop_select_down.is-multiple .selectbox {
  display: block;
  height: 34px;
  line-height: 34px;
}
.pop_select_down.is-multiple .el-select-dropdown__item.selected::after {
  top: 0.05rem;
  left: 1.17rem;
  z-index: 1;
  font-weight: normal;
  color: #fff;
}
.pop_select_down.is-multiple .el-select-dropdown__item .check {
  position: relative;
  box-sizing: border-box;
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
  margin-right: 10px;
  vertical-align: middle;
  border: 1px solid #656c7e;
  border-radius: 2px;
  transition: border-color 0.25s cubic-bezier(0.71, -0.49, 0.26, 1.46),
    background-color 0.25s cubic-bezier(0.71, -0.49, 0.26, 1.46);
}
.pop_select_down.is-multiple .el-select-dropdown__item.selected .check {
  background-color: #656c7e;
}
</style>

使用组件

<span>产品名称:</span>
<selectCheckBox
          ref="selectCheckBox"
          placeholder="请选择产品代码或名称"
          class-name="filterWidth"
          :model-ori="productCode"
          :options="productCodeList"
          :options-ori="productCodeList"
          opl="label"
          opv="id"
          @selectChange="productNameChange"
></selectCheckBox>

//  单独写个change事件 实现子组件的值回传给父组件 给父组件对应值赋值

    productNameChange(v) {
      this.productCode = v;
    }

根据编码自动选中功能

主要是遍历options,根据输入的值 做匹配,代码写的很繁琐,为了适用多用情况加了很多参数和判断,故不附代码;

测试过程中出现的问题:
发现名称不一致,但是编码却相同,所以就导致filter-methods方法报错,(报错内容是关于key未定义),所以在el-option上:key时加了个随机数。