首先放上el-select的官网地址,对这块知识不是很清楚的可以先看下这里select选择器
之前项目有个需求是这样的:多选的情况下显示两个tag,其余的tag以数字形式展示,并且当鼠标悬浮在数字上时可以看到所有选中的值。
而选择器多选的效果只能显示成这样
那就只能封装一个新的组件来满足业务需求,话不多说,直接上代码:
<template>
<div class="v-multiple-select">
<el-select v-model="value" multiple placeholder="请选择" value-key="userId" :size="size" @change="handleChange">
<el-option label="全选" value="all" @click.native="selectAll" v-if="isShowSelectAll"></el-option>
<el-option v-for="item in options" :key="item[listValue]" :label="item[listLabel]" :value="item"></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>
<!-- <div class="popover" v-show="isPopover"> -->
<div class="popover" v-if="isPopover">
<el-popover placement="top-start" title="已选中" width="200" trigger="hover" :content="value.map(i => i[listLabel]).join(',') || '暂未选择'">
<span class="tag-length" slot="reference">{{ '+' + tagsLength }}</span>
</el-popover>
</div>
</div>
</template>
</el-select>
</div>
</template>
<script>
import { isObjectValueEqual } from '@/utils/common'
export default {
name: 'MutipleSelect',
data() {
return {
// 真正的选中人员数组
value: this.list ? this.list : [],
// 限制展示数量的人员数组
tags: [],
tagsLength: null,
// 判断是否显示弹出框
isPopover: false
}
},
props: {
options: {
// select的下拉数据
type: Array,
default: () => []
},
list: {
// 选中数据
type: Array,
default: () => []
},
listValue: {
// 数据值的key字段,默认value
type: String,
default: 'value'
},
listLabel: {
// 数据显示文本的key字段,默认label
type: String,
default: 'label'
},
maxTag: {
// 文本框显示最大tag数
type: String,
default: '3'
},
size: {
// select的size
type: String,
default: 'small'
},
isShowSelectAll: {
// 是否有全选选项
type: Boolean,
default: false
}
// width: {
// // select的宽度
// type: String,
// default: '2rem'
// }
},
watch: {
list: {
handler(newVal, oldVal) {
if (!isObjectValueEqual(newVal, oldVal) && newVal) {
this.value = newVal
this.tags = newVal.length > parseInt(this.maxTag) ? newVal.slice(0, parseInt(this.maxTag)) : newVal
this.tagsLength = newVal.length > parseInt(this.maxTag) ? newVal.length - parseInt(this.maxTag) : null
}
if (!newVal) {
this.value = newVal
this.tags = newVal
this.tagsLength = null
}
},
deep: true
// immediate: true
},
tagsLength() {
if (!this.tagsLength) this.isPopover = false
else this.isPopover = true
}
},
mounted() {
if (this.list) {
this.tags = this.list.length > parseInt(this.maxTag) ? this.list.slice(0, parseInt(this.maxTag)) : this.list
} else this.tags = null
this.tagsLength = this.value.length > parseInt(this.maxTag) ? this.value.length - parseInt(this.maxTag) : null
},
methods: {
removeTag(v) {
// this.value.splice(this.value.indexOf(v), 1)
const t = []
this.value.forEach(item => {
if (item.userId !== v) t.push(item)
})
this.value = t
this.handleChange(this.value)
},
handleChange(arr) {
// if (arr.length < parseInt(this.maxTag) || arr.length < this.tags.length) this.tags = arr
if (arr.length <= parseInt(this.maxTag) || arr.length <= this.tags.length) this.tags = arr
if (arr.length < this.tags.length + parseInt(this.tagsLength)) {
this.tags = arr.slice(0, arr.length - parseInt(this.tagsLength) + 1)
}
this.tagsLength = this.value.length > parseInt(this.maxTag) ? this.value.length - parseInt(this.maxTag) : null
this.$emit('update:list', arr)
},
selectAll() {
if (this.value.length === this.options.length) {
this.value = []
this.tags = []
this.tagsLength = null
} else {
const arr = this.options.slice(1).filter(item => {
return this.value.every(item1 => {
return item.userId !== item1.userId
})
})
this.value = this.value.concat(arr)
this.tags = this.value.slice(0, parseInt(this.maxTag))
this.tagsLength = this.value.length - parseInt(this.maxTag)
}
this.$emit('update:list', this.value)
}
}
}
</script>
<style lang="scss" scoped>
.v-multiple-select {
position: relative;
display: flex;
width: 100%;
}
/* .v-multiple-select .el-select {
overflow: hidden;
} */
/* .v-multiple-select .el-select__tags {
display: none;
} */
.popover {
// width: 10%;
display: contents;
align-items: center;
justify-content: center;
}
.v-multiple-select .max-tag {
width: 100%;
height: 100%;
/* 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: 0.15rem;
}
.tag-length {
display: inline-block;
color: #ec7259;
margin-left: 0.02rem;
}
/deep/ .el-select__tags {
display: none;
}
/deep/ .el-select .el-tag {
display: initial;
font-size: 0.13rem;
overflow: hidden;
text-overflow: ellipsis;
}
/deep/ .el-select .el-tag .el-icon-close {
top: -0.02rem;
}
</style>
props里的一些变量都是需要父组件传入的,在使用这个组件的时候需要斟酌一下应该怎么传,css我这样写也是因为项目配置了一些默认的样式,我需要覆盖掉原本的样式,所以样式这块可能也要按需调整一下。注释也有解释设置变量的目的,所以应该还是比较好懂的吧,就不再多解释了233
如果有疑惑或者觉着这个组件有可以优化的地方,欢迎留言讨论~祝大家秃头愉快