el-select组件改造成多选显示多个标签加数字标签的形式
接到需求需要只在一行内显示多个标签,且标签超出输入框时超出的标签不显示,只显示统计数字的标签。
效果图:

网上查资料,发现一篇大佬的文章跟该需求很类似,就借用了大佬的写法,文章链接看这里。
后面发现还是有两个地方需要做下微调整。
1、需要数字标签紧跟着文字标签的后面排列,不能一直固定在右边
2、当页面同时有多个el-select组件时目前的写法会监听不到我们想监听的el-select组件,所以必须要保证被监听的组件的唯一性
调整后的代码如下:
html
<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>
props
props: {
options: {
type: Array,
default: () => []
},
value: {
type: Array,
default: () => []
}
}
mounted
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() {
this.$emit("change", this.value);
}
},
computed: {
values: {
get() {
return this.value;
},
set(val) {
this.$emit("input", val);
}
}
},
//销毁时
beforeDestroy() {
// 停止观察
observer.disconnect();
}
style
<style>
.count-node {
position: absolute;
top: 2px;
display: none;
height: 24px;
padding: 0 8px;
line-height: 22px;
margin-left: 6px;
background-color: #f4f4f5;
border: 1px solid #e9e9eb;
border-radius: 4px;
color: #909399;
font-size: 12px;
box-sizing: border-box;
}
</style>
父组件引用
html
设置的class类名‘select-tags’用于保证获取组件需要监听的元素的唯一性
<select-tags
v-model="value1"
:options="options"
class="select-tags"
></select-tags>
data
options: [{
value: '选项1',
label: '黄金糕'
}, {
value: '选项2',
label: '双皮奶'
}, {
value: '选项3',
label: '蚵仔煎'
}, {
value: '选项4',
label: '龙须面'
}, {
value: '选项5',
label: '北京烤鸭'
}],
value1: [],

浙公网安备 33010602011771号