前端:“这需求是认真的吗?” —— el-select 的动态宽度解决方案
Hello~大家好。我是秋天的一阵风 ~
前言
最近我遇到了一个神奇的需求,客户要求对 el-select 的 宽度 进行动态设置。
简单来说,就是我们公司有一些选择框,展示的内容像“中华人民共和国/广西壮族自治区/南宁市/西乡塘区”
这么长,一不小心就会内容超长,显示不全。详情请看下面动图:
一般来说,想解决内容展示不全的问题,有几种方法。
第一种:给选择框加个tooltip
效果,在鼠标悬浮时展示完整内容。
第二种:对用户选择label值进行切割,只展示最后一层内容。
但是我们的客户对这两种方案都不接受,要求选择的时候让select选择框的宽度动态增加。
有什么办法呢?客户就是上帝,必须满足,他们说什么就是什么,所以我们只能开动脑筋,动手解决。
思路
我们打开控制台,来侦察一下el-select
的结构,发现它是一个el-input--suffix
的div
包裹着一个input
,如下图所示。
内层input
的宽度是100%,外层div
的宽度是由这个内层input
决定的。也就是说,内层input
的宽度如果动态增加,外层div
的宽度也会随之增加。那么问题来了,如何将内层input
的宽度动态增加呢?
tips:
如果你对width的100%和auto有什么区别感兴趣,可以点击查看我之前的文章
解决方案
为了让我们的el-select
宽度能够跟着内容走,我们可以在内层input
同级别增加一个元素,内容就是用户选中的内容。内容越多,它就像一个胃口很大的小朋友,把外层div的宽度撑开。下面来看图示例 :
借助prefix
幸运的是,el-select
本身有一个prefix的插槽选项,我们可以借助这个选项实现:
我们添加一个prefix
的插槽,再把prefix
的定位改成relative
,并且把input
的定位改成绝对定位absolute
。最后将prefix
的内容改成我们的选项内容。看看现在的效果:
<template>
<div>
<el-select class="autoWidth" v-model="value" placeholder="请选择">
<template slot="prefix">
{{optionLabel}}
</template>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
options: [
{
value: "选项1",
label: "中华人民共和国/广东省/深圳市/福田区",
},
{
value: "选项2",
label: "中华人民共和国/广西壮族自治区/南宁市/西乡塘区",
},
{
value: "选项3",
label: "中华人民共和国/北京市",
},
{
value: "选项4",
label: "中华人民共和国/台湾省",
},
{
value: "选项5",
label: "中华人民共和国/香港特别行政区",
},
],
value: "",
};
},
computed: {
optionLabel() {
return (this.options.find((item) => item.value === this.value) || {})
.label;
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .autoWidth .el-input__prefix {
position: relative;
}
::v-deep .autoWidth input {
position: absolute;
}
</style>
细节调整
现在el-select
已经可以根据选项label的内容长短动态增加宽度了,但是我们还需要继续处理一下细节部分,将prefix
的内容调整到和select
框中的内容位置重叠
,并且将它隐藏
。看看现在的效果
::v-deep .autoWidth .el-input__prefix {
position: relative;
box-sizing: border-box;
border: 1px solid #fff;
padding: 0 30px;
height: 40px;
line-height: 40px;
left: 0px;
visibility: hidden;
}
调整初始化效果(用户未选择内容)
目前已经基本实现了效果了,还有最后一个问题,当用户没有选择内容的时候,select的宽度是“没有”
的,如下图所示。
所以我们还得给他加上一个最小宽度
我们加上最小宽度以后,发现这个select的图标又没对齐,这是因为我们在重写.el-input__prefix
样式的时候设置了padding: 0 30px,
当用户没有选择内容的时候,select
的图标应该是默认位置,我们需要继续调整代码,最后效果如下图所示:
完整代码
最后附上完整代码:
<template>
<div>
<el-select
class="autoWidth"
:class="{ 'has-content': optionLabel }"
v-model="value"
placeholder="请选择"
clearable
>
<template slot="prefix">
{{ optionLabel }}
</template>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
options: [
{
value: "选项1",
label: "中华人民共和国/广东省/深圳市/福田区",
},
{
value: "选项2",
label: "中华人民共和国/广西壮族自治区/南宁市/西乡塘区",
},
{
value: "选项3",
label: "中华人民共和国/北京市",
},
{
value: "选项4",
label: "中华人民共和国/台湾省",
},
{
value: "选项5",
label: "中华人民共和国/香港特别行政区",
},
],
value: "",
};
},
computed: {
optionLabel() {
return (this.options.find((item) => item.value === this.value) || {})
.label;
},
},
};
</script>
<style lang="scss" scoped>
.autoWidth {
min-width: 180px;
}
::v-deep .autoWidth .el-input__prefix {
position: relative;
box-sizing: border-box;
border: 1px solid #fff;
padding: 0 30px;
height: 40px;
line-height: 40px;
left: 0px;
visibility: hidden;
}
::v-deep .autoWidth input {
position: absolute;
}
.autoWidth {
// 当.has-content存在时设置样式
&.has-content {
::v-deep .el-input__suffix {
right: 5px;
}
}
// 当.has-content不存在时的默认或备选样式
&:not(.has-content) {
::v-deep .el-input__suffix {
right: -55px;
}
}
}
</style>
来源:juejin.cn/post/7385825759118196771