vue 封装el-select多选下拉框(可用输入框搜索过滤)

vue 封装el-select多选下拉框(可用输入框搜索过滤)

下拉筛选效果如下
在这里插入图片描述

代码部分
html部分
  1. 创建多选组件 mSelect.vue
<template>
  <el-select
    ref="select"
    v-model="hValue"
    multiple
    collapse-tags
    :clearable="clearable"
    :disabled="disabled"
    :placeholder="placeholder"
    :popper-class="selectInfo.align == 'left'
        ? 'select-default select-text-align-left no-empty'
        : 'select-default no-empty'
    "
    :key="poperKeyValue"
    :value-key="valueKey"
    @blur="handleBlur"
    @change="handleChange"
    @clear="handleClear"
    @focus="handleFocus"
    @remove-tag="handleRemoveTag"
    @visible-change="handleVisibleChange"
  >
    <el-input
      class="filter-input"
      v-model.trim="hFilterVal"
      v-if="filterable"
      :class="selectInfo.options.length == 0 ? 'filter-input-mb' : ''"
    ></el-input>

    <el-checkbox-group v-model="hValue">
      <el-option
        v-for="(item, index) in selectInfo.options"
        :key="index"
        :label="
          selectInfo.prop && selectInfo.prop.label
            ? item[selectInfo.prop.label]
            : item.name
        "
        :disabled="item.disabled"
        :value="
          selectInfo.prop && selectInfo.prop.value
            ? item[selectInfo.prop.value]
            : item.id
        "
      >
        <el-checkbox
          style="pointer-events: none"
          :label="
            selectInfo.prop && selectInfo.prop.value
              ? item[selectInfo.prop.value]
              : item.id
          "
          >{{
            selectInfo.prop && selectInfo.prop.label
              ? item[selectInfo.prop.label]
              : item.name
          }}
        </el-checkbox>
      </el-option>
    </el-checkbox-group>
  </el-select>
</template>

<script>
export default {
  name: "HSelectMul",
  props: {
    placeholder: String,
    selectInfo: {
      type: Object,
      default() {
        return {
          align: "left",
          options: [],
          prop:{
            label:'name',
            value:'id'
          }
        };
      }
    },
    filterVal:{
      type:String,
      value:''
    },
    clearable: {
      type: Boolean,
      default: true
    },
    disabled: {
      type: Boolean,
      default: false
    },
    filterable: {
      type: Boolean,
      default: true
    },

    value: {
      type: [String, Number, Array, Boolean],
      required: true
    },
    valueKey: String,

    keyValue: {
      type: String,
      default: "select-single"
    }
  },
  data() {
    return {
      poperKeyValue: ""
    };
  },
  computed: {
    hValue: {
      get() {
        let value = [];
        if (this.value instanceof Array) {
          this.value.forEach(key => {
            if (this.checkValueExisting(key)) {
              value.push(key);
            }
          });
        }
        return value;
      },
      set(value) {
        this.$emit("input", value);
      }
    },
    hFilterVal: {
      get() {
        return this.filterVal;
      },
      set(value) {
        this.$emit("input-search", value);
      }
    },
  },
  watch: {
    keyValue(val) {
      this.poperKeyValue = val;
    }
  },
  methods: {
    checkValueExisting(value) {
      let key = this.selectInfo.prop&&this.selectInfo.prop.value?this.selectInfo.prop.value:'id'
      if(this.filterable) {
        if (this.selectInfo.filterOptions instanceof Array) {
          let index = this.selectInfo.filterOptions.findIndex(
              item => item[key] === value,
              this
          );
          return index > -1;
        }
      } else {
        if (this.selectInfo.options instanceof Array) {
          let index = this.selectInfo.options.findIndex(
              item => item[key] === value,
              this
          );
          return index > -1;
        }
      }

      return false;
    },
    handleBlur(event) {
      this.$emit("blur", event);
    },
    handleChange(value) {
      this.$emit("change", value);
    },
    handleClear() {
      this.$emit("clear");
    },
    handleFocus(event) {
      this.$emit("focus", event);
    },
    handleRemoveTag(tag) {
      this.$emit("remove-tag", tag);
    },
    handleVisibleChange(visible) {
      this.$emit("visible-change", visible);
    }
  }
};
</script>

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

  1. 在父组件中引用
<template>
  <div>
    <m-select
        :select-info="info"
        v-model="formData.form[info.field]"
        :filter-val="info.filterVal"
        @input-search="dropDownSearchTop"
        @change="changeSelect"
    >
    </m-select>
  </div>
</template>
<script>
  import MSelect from "@/harley-ui/selectMultiple/index";
  export default {
    data() {
      return {
        info: {
          filterOptions:[],
          options: [],
          filterVal: '',
          chooseSelectList:[],
          prop:{
            label:'name',
            value:'id'
          }
        }
      }
    },
    components:{MSelect},
    methods:{
      changeSelect(val) {
        console.log(val, "kkkkk");
        this.info.chooseSelectList = [];
        for (let i = 0; i < info.filterOptions.length; i++) {
          for (let j = 0; j < val.length; j++) {
            let value = info.prop && info.prop.value ? info.prop.value : "id";
            if (val[j] === info.filterOptions[i][value]) {
              info.chooseSelectList.push(info.filterOptions[i]);
            }
          }
        }

      },

      dropDownSearchTop(val) {
        this.info.filterVal = val;
        if (this.info.filterVal === "") {
          this.info.options = JSON.parse(JSON.stringify(this.info.filterOptions));
          return;
        }
        let list = [];
        if (this.info.chooseSelectList.length > 0) {
          list = info.filterOptions.filter(item => {
            let value = this.info.prop && this.info.prop.value ? this.info.prop.value : "id";
            return info.chooseSelectList.every(el => el[value] != item[value]);
          });
        } else {
          list = JSON.parse(JSON.stringify(this.info.filterOptions));
        }
        this.info.options = this.info.chooseSelectList.concat(
            list.filter(item => {
              let name = this.info.prop && this.info.prop.label ? this.info.prop.label : "name";
              return item[name].includes(this.info.filterVal);
            })
        );
      },
    }
  }
</script>

css部分
.select-default {
  background-color: #43504a;
  color: #45494d;
  border: 1px solid #43504a;

 &.select-text-align-left {
    .el-scrollbar__wrap {
      .el-select-dropdown__list {
        .el-select-dropdown__item {
          text-align: left;
        }
      }
    }
  }
  &.no-empty {
    .el-scrollbar {
      display: block !important;
      .el-scrollbar__wrap {
        // overflow-y: scroll;
        // overflow-x: hidden;
        // margin-bottom: vh(-6) !important;
        // margin-right: vw(-6) !important;
        .el-select-dropdown__list {
          .filter-input {
            height: 50px;
            width: 84%;
            margin-bottom: 30px;
            margin-left: 30px;
            &.filter-input-mb {
              margin-bottom: 10px;
            }
            .el-input__inner {
              width: 100%;
              height: 100%;
              color:#fff;
              border: 1px solid #fff !important;
              font-size: 24px;
            }
          }
        }
      }
    }
  }

  .el-scrollbar__wrap {
   
    max-height: 404px;
    .el-select-dropdown__list {
      padding: 6px 0;
      
      .el-checkbox-group {
        display: flex;
        justify-content: center;
        flex-direction: column;
        height: 100%;

        .el-checkbox {
          width: fit-content;
          padding: 0;
          display: inline-flex;
          align-items: center;
          height: 100%;
          font-size: 24px;
          margin-right: vw(30);

          .el-checkbox__label {
            font-size: 24px;
            padding-left: 13px;
            color: #fff;
            display: flex;
            align-items: center;
            height: 100%;
          }

          .el-checkbox__input {
            display: inline-flex;
            align-items: center;
            justify-content: center;

            &.is-checked {
              .el-checkbox__inner {
                background: url("勾选的图片");
                width: 33px;
                height: 33px;
                border: none;
              }

              + .el-checkbox__label {
                color: #fff;
              }
            }

           

            &.is-disabled {
              .el-checkbox__inner {
                background: url("禁用的图片");
                width: 33px;
                height: 33px;
              }
              &.is-checked {
                .el-checkbox__inner {
                  background: url("勾选的图片");
                  width: 33px;
                  height: 33px;
                  border: none;
                }

                + .el-checkbox__label {
                  color: #fff;
                }
              }
            }

            .el-checkbox__inner {
              background: url("未勾选的图片");
              width: 33px;
              height: 33px;
            }
          }
        }
      }

      .el-select-dropdown__item {
        font-size: 24px;
        padding: 0 20px;
        color: #fff;
        height: 38px;
        line-height: 38px;
        text-align: center;
        font-weight: 100;
        margin-bottom: 20px;
        box-sizing: border-box;
        cursor: pointer;
        &:last-child {
          margin-bottom: 0;
        }

        &.is-disabled {
          color: #75837c;
          cursor: not-allowed;

          &:hover {
            background: transparent !important;
            color: #75837c !important;
            font-weight: 100;
          }
          .el-checkbox {
            opacity: 0.7;
          }
        }

        &:hover {
          background: #808c87 !important;
          color: #fff !important;
          height: 38px;
        }

        &.hover {
          background: transparent !important;
          color: #fff !important;
          height: 38px;
          &:hover {
            background: #808c87 !important;
            color: #fff !important;
            height: 38px;
          }
        }

        &.selected {
          background: #808c87 !important;
          color: #fff !important;
          height: 38px;

          &.hover {
            background: #808c87 !important;
          }
        }
      }
    }
  }
}

传参属性解读

  • filterOptions — 存储原始的下拉绑定的list,用来过滤(输入框改变的时候需要取到所有的数据进行筛选然后展示,所以该属性需要存储所有的下拉选的值)
  • options — 下拉选绑定的list
  • filterVal — 输入框绑定的值
  • prop — 获取选中取值的key用那个字段
  • chooseSelectList — 现在已经选中的下拉集合(在dropDownSearchTop方法中,之所以要拼接上chooseSelectList.concat是为了避免绑定的options中没有之前选中的值,页面展示不出来之前选中值的名称)

类名解读

  • no-empty
    • 当我们模糊搜索时如果未匹配到相符合的数据,el-select展示暂无数据且将el-scrollbar下的内容全部隐藏掉,所以我们需要先把el-scrollbar样式设为block,否则输入框会被隐藏掉
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值