高度自适应
在element-ui的文档中可以看到,多选时,高度自适应是默认就有的展示方式,select组件不需要设置额外属性,如下图显示:
<el-select class="select" v-model="value" multiple placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
正常情况下高度自适应已经足够使用了,但是如果option文字过多,tag横向展示时,就会出现超出输入框的异常显示情况,如下图所见:
解决方法:
修改css样式,修改tag宽度样式,增加文字超出显示省略号,代码如下:
<style lang="scss" scoped>
.el-select.select{
::v-deep .el-select__tags {
.el-tag {
display: flex;
align-items: center;
width: auto !important;
max-width: 100% !important;
flex-wrap: nowrap !important;
.el-select__tags-text {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
}
}
}
}
</style>
效果显示如下,当option宽度大于选择框宽度时,tag内部显示省略号:
宽度自适应
宽度自适应和高度自适应是二选一的,所以宽度自适应的时候给高度增加限制,然后计算tag的宽度来实现宽度自适应;
解决方法:
<el-select
ref="select"
v-model="selectVal"
class="select"
multiple
:class="{isAutoWidth: isAutoWidth}"
:style="{'width': `${selectWid}px !important`}"
:collapse-tags="!isAutoHeight && !isAutoWidth"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
监听value值的变化,计算每一个tag的宽度总和,包括内外边距、边框宽度,动态绑定,如下:
data() {
return {
isAutoWidth: true, // 判断是否为宽度自适应
selectWidth: 206, // select框默认宽度
selectWid: 0, // 实际宽度
padRight: 0, // input的padding-right
itemsMLeft: 0, // tag之间的margin
itemsMRight: 0, // tag之间的margin
borderL: 0, // input边框
borderR: 0, // input边框
itemBborderL: 0, // tag边框
itemBborderR: 0, // tag边框
}
},
watch: {
// select框最小宽度
selectWidth: {
deep: true,
handler(n) {
this.selectWid = n;
},
immediate: true
},
value: {
deep: true,
handler(n) {
this.$nextTick(()=> {
// 获取全部tag的vnode
const tagArr = this.$refs.select.$children[0].$children;
// querySelector() 方法返回文档中匹配指定 CSS 选择器的一个元素。
const childTag = this.$refs.select.$el.querySelectorAll('.el-tag');
// 获取每个tag的宽度
// clientWidth: 实际显示宽度+padding
// offsetWidth: 实际显示宽度+padding+border
const tagWidArr = tagArr.map(item=> {
return item.$el.clientWidth;
});
// tag总宽度
let allWid = 0;
const tagMargin = this.itemsMLeft + this.itemsMRight; // tag之间的margin
const tabBorder = this.itemBborderL + this.itemBborderR; // tag边框
const inpBorder = this.borderL + this.borderR; // input边框
tagWidArr.forEach(item=> {
allWid += (item + tagMargin + tabBorder); // tagMargin为tag之间的margin, 2为border
});
const tagWid = allWid + this.padRight; // 30为input padding-right
// 判断是否为宽度自适应需求
if (this.isAutoWidth) {
this.selectWid = (allWid > this.selectWidth) ? tagWid : this.selectWidth;
} else {
this.selectWid = this.selectWidth;
// 这个功能是用来使显示不开的第一个tag进行省略号处理
if (childTag.length) {
childTag.forEach((item, index)=> {
let tagBoxWid = 0;
/**
* 8*2代表两个tag的margin + border
* padRight 代表input内边距
* 2写死的,这个是显示一个显示不开的那种情况(某个border)
*/
if (this.isAutoHeight) {
tagBoxWid = this.selectWid - (tagMargin + tabBorder) - this.padRight - inpBorder;
} else {
// tag显示collapse-tags合并样式
tagBoxWid = childTag.length === 1 ?
this.selectWid - (tagMargin + tabBorder) - this.padRight - inpBorder :
this.selectWid - childTag[1].clientWidth - (tagMargin + tabBorder) * 2 - this.padRight - inpBorder;
}
item.style.maxWidth = tagBoxWid + 'px';
});
}
}
}
}
}