注册
web

前端:“这需求是认真的吗?” —— el-select 的动态宽度解决方案

Hello~大家好。我是秋天的一阵风 ~


前言


最近我遇到了一个神奇的需求,客户要求对 el-select宽度 进行动态设置。


简单来说,就是我们公司有一些选择框,展示的内容像“中华人民共和国/广西壮族自治区/南宁市/西乡塘区”这么长,一不小心就会内容超长,显示不全。详情请看下面动图:


1.gif


一般来说,想解决内容展示不全的问题,有几种方法。


第一种:给选择框加个tooltip效果,在鼠标悬浮时展示完整内容。


第二种:对用户选择label值进行切割,只展示最后一层内容。


但是我们的客户对这两种方案都不接受,要求选择的时候让select选择框的宽度动态增加。


有什么办法呢?客户就是上帝,必须满足,他们说什么就是什么,所以我们只能开动脑筋,动手解决。


思路


我们打开控制台,来侦察一下el-select的结构,发现它是一个el-input--suffixdiv包裹着一个input,如下图所示。


image.png

内层input的宽度是100%,外层div的宽度是由这个内层input决定的。也就是说,内层input的宽度如果动态增加,外层div的宽度也会随之增加。那么问题来了,如何将内层input的宽度动态增加呢?



tips:


如果你对width的100%和auto有什么区别感兴趣,可以点击查看我之前的文章


探究 width:100%与width:auto区别



解决方案


为了让我们的el-select宽度能够跟着内容走,我们可以在内层input同级别增加一个元素,内容就是用户选中的内容。内容越多,它就像一个胃口很大的小朋友,把外层div的宽度撑开。下面来看图示例 :


image.png

借助prefix


幸运的是,el-select本身有一个prefix的插槽选项,我们可以借助这个选项实现:


image.png

我们添加一个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>



2.gif

细节调整


现在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;
}

3.gif

调整初始化效果(用户未选择内容)


目前已经基本实现了效果了,还有最后一个问题,当用户没有选择内容的时候,select的宽度是“没有”的,如下图所示。


image.png

所以我们还得给他加上一个最小宽度


image.png

我们加上最小宽度以后,发现这个select的图标又没对齐,这是因为我们在重写.el-input__prefix样式的时候设置了padding: 0 30px,当用户没有选择内容的时候,select的图标应该是默认位置,我们需要继续调整代码,最后效果如下图所示:


4.gif

完整代码


最后附上完整代码:



<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

0 个评论

要回复文章请先登录注册