该组件用于解决el-select的tag展示,将两者结合,当多选超出宽度时使用+1的方式展示,在原作者的基础上做了修改
功能实现如下
子组件
<template>
<!-- el-select组件的二次封装,用于处理标签超出时省略展示 -->
<el-select
v-model="values"
multiple
style="width: 100%"
placeholder="请选择"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</template>
<script>
var observer = null
export default {
props: {
options: {
type: Array,
default: () => []
},
value: {
type: Array,
default: () => []
}
},
data() {
return {}
},
mounted() {
let tagLIstDom = document.querySelector('.el-select__tags')
// 需要加上组件自定义的类名,防止监听失效
let tagSpanDom = document.querySelector(
'.select-tags .el-select__tags > span'
)
let hideDom = document.createElement('span')
hideDom.classList = ['count-node'] //设置样式
tagSpanDom.append(hideDom) //插入到span中
var config = { childList: true }
// 当观察到突变时执行的回调函数
var callback = function (mutationsList) {
mutationsList.forEach(function (item, index) {
if (item.type == 'childList') {
let tagList = item.target.childNodes
let tagWidth = 0 //标签总宽度
let tagNum = 0 //标签多余个数
let avaliableTagWidth = 0 //显示标签的总宽度
for (let i = 0; i < tagList.length; i++) {
const e = tagList[i]
if (tagWidth > tagLIstDom.offsetWidth) {
e.style.display = 'none' //隐藏多余标签
} else {
e.style.display = 'inline-block' //显示标签
}
tagWidth += e.offsetWidth + 5
if (tagWidth > tagLIstDom.offsetWidth) {
e.style.display = 'none' //隐藏多余标签
} else {
e.style.display = 'inline-block' //显示标签
}
if (e.style.display != 'none') {
tagNum++
hideDom.style.display = 'none' //隐藏多余标签个数
const margin = tagNum === 1 ? 0 : 7
avaliableTagWidth += e.offsetWidth + margin
} else {
hideDom.style.display = 'inline-block' //显示多余标签个数
hideDom.style.left = `${avaliableTagWidth}px` //数字标签的位置设置
hideDom.innerHTML = `+${tagList.length - tagNum}` //显示多余标签个数
}
}
}
})
}
// 创建一个链接到回调函数的观察者实例
observer = new MutationObserver(callback)
// 开始观察已配置突变的目标节点
observer.observe(tagSpanDom, config)
// 随后,您还可以停止观察
// observer.disconnect();
},
methods: {
handleChange(val) {
//原作者此处直接使用this.value,会出现bug,点击第一次是this.value还未绑定,故第二次点击才会记录第一次的值
this.value = val//修改
this.$emit('change', this.value)
}
},
computed: {
values: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
//销毁时
beforeDestroy() {
// 停止观察
observer.disconnect()
}
}
</script>
<style>
.count-node {
position: absolute;
top: 2px;
display: none;
height: 20px;
padding: 0 6px;
line-height: 20px;
margin-left: 0px;
background-color: #f4f4f5;
border: 1px solid #e9e9eb;
border-radius: 4px;
color: #909399;
font-size: 12px;
box-sizing: border-box;
}
</style>
父组件
设置的class类名‘select-tags’用于保证获取组件需要监听的元素的唯一性
<leSelect
@change="oneSandChange"
style="width: 300px"
v-model="oneSandId"
:options="oneSandNumberList"
class="select-tags"
></leSelect>