二次封装element多选select

1,592 阅读1分钟

因为业务需要用到element多选select组件,但是多选的el组件,只有下面这两种:

但是产品希望的尽可能单行显示,行内尽可能显示多项,超出才用数字显示,具体效果如下:

好了,废话不多说,直接贴组件代码:

/**
* 二次封装的select组件,这里命名为vMutipleSelect
*/
<template>
   <div class="v-multiple-select">
        <el-select v-model="value" multiple placeholder="请选择" :size="size" @change="handleChange" :style="'width:' + width">
           <el-option label="全选" value="all" @click.native="selectAll" v-if="isShowSelectAll"></el-option> 
           <el-option
           v-for="item in list"
           :key="item[listValue]"
           :label="item[listLabel]"
           :value="item[listValue]">
           </el-option>
           <template slot = "prefix">
               <div class="max-tag">
                   <el-tag v-for="tag in tags" :key="tag[listValue]" closable type="info" @close="removeTag(tag[listValue])" size="small">{{tag[listLabel]}}</el-tag>
                   <span class="tag-length">{{tagsLength ? '+' + tagsLength : ''}}</span>
               </div>
           </template>
       </el-select>
   </div>
</template>

<script>
export default {
 name: 'vMultipleSelect',
 data () {
   return {
       value: '',
       tags: [],
       tagsLength: ''
   };
 },
 props: {
   list: { // select的下拉数据
     type: Array,
     default: () => []
   },
   listValue: { // 数据值的key字段,默认value
     type: String,
     default: 'value'
   },
   listLabel: { // 数据显示文本的key字段,默认label
     type: String,
     default: 'label'
   },
   maxTag: { // 文本框显示最大tag数
       type: String,
       default: '2'
   },
   size: { // select的size
       type: String,
       default: 'small'
   },
   isShowSelectAll: { // 是否有全选选项
       type: Boolean,
       default: true
   },
   width: { // select的宽度
       type: String,
       default: '180px'
   }
 },
 mounted () {
 },
 methods: {
     removeTag (v) {
         this.value.splice(this.value.indexOf(v), 1);
         this.handleChange(this.value);
     },
     handleChange (arr) {
         this.tags = [];
         for (let i = 0; i < this.list.length; i++) {
             if (this.tags.length === parseInt(this.maxTag)) break;
               if (arr.indexOf(this.list[i][this.listValue]) > -1) {
                   this.tags.push(this.list[i]);
               }
         }
         this.tagsLength = this.value.length > this.tags.length ? this.value.length - this.tags.length : '';
         this.$emit('getSelectValue', this.value);
     },
     selectAll () {
         let valueLen = this.value.length;
         this.tags = [];
         this.value = [];
         if (valueLen === this.list.length + 1) {
             this.$emit('getSelectValue', this.value);
             this.tagsLength = '';
             return;
         }
         for (let i = 0; i < this.list.length; i++) {
             if (i < parseInt(this.maxTag)) {
               this.tags.push(this.list[i]);
             }
             this.value.push(this.list[i][this.listValue]);
         }
         this.tagsLength = this.value.length > this.tags.length ? this.value.length - this.tags.length : '';
         this.$emit('getSelectValue', this.value);
     }
 }
};
</script>
<style >
.v-multiple-select {
   position: relative;
   display: flex;
}
.v-multiple-select .el-select {
   overflow: hidden;
}
.v-multiple-select .el-select__tags {
 display: none;
}

.v-multiple-select .max-tag {
   overflow: hidden;
}
.v-multiple-select .max-tag .el-tag.el-tag--info .el-tag__close {
   background-color: #C0C4CC;
}
.v-multiple-select .el-input--prefix .el-input__inner {
   padding-left: 15px;
}
.v-multiple-select .max-tag .tag-length {
   color: #ec7259;
   margin-left: 2px;
}
</style>

使用组件:

 /**
* 使用组件
*/
<template>
  <div class="hello">
    <v-multiple-select :list=options listValue='value' listLabel='label' maxTag='3' @getSelectValue="getSelectValue" width="200px" />
  </div>
</template>

<script>
import vMultipleSelect from './multipleSelect';
export default {
  name: 'HelloWorld',
  components: {
    vMultipleSelect
  },
  data () {
    return {
      options: [{
          value: '1',
          label: '1'
        }, {
          value: '2',
          label: '2'
        }, {
          value: '3',
          label: '3'
        }, {
          value: '4',
          label: '4'
        }, {
          value: '5',
          label: '5'
        }]
    }
  },
  methods: {
    getSelectValue(v) {
      console.log(v);
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

这个组件,其实还可以根据实际项目中select宽度,自动默认tag显示数量。获取已选中tag宽度和select作对比,这个后续可以自己做扩展。