在移动端日常开发中经常会遇到这样一个场景,在一个列表中,左边是一张固定大小的图片,右边是一行或多行文字,宽度自适应,溢出省略,如下图
看到这个样式,略一思考,貌似用弹性布局就可以实现,左边固定宽度,右边设置flex:1。
html:
<div class="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<img class="item-img" :src="item.imgs" />
<div class="item-box">{{ item.title }}</div>
</div>
</div>
css:
.list-item{
width: 100%;
height:80px;
padding-left: 10px;
padding-right: 10px;
box-sizing: border-box;
display:flex;
align-items: center;
}
.item-img{
width:36px;
height:36px;
margin-right: 10px;
}
.item-box{
flex:1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
效果:
貌似成功了一半,右边一行内容的情况下已经实现了需要的效果。那么,右边是多行呢?
html:
<div class="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<img class="item-img" :src="item.imgs" />
<div class="item-box">
<div class="item-title fn-text-overflow">{{ item.title }}</div>
<div class="item-remark fn-text-overflow">{{ item.remark }}</div>
</div>
</div>
</div>
css:
.list-item{
width: 100%;
height:80px;
padding-left: 10px;
padding-right: 10px;
box-sizing: border-box;
display:flex;
align-items: center;
}
.item-img{
width:36px;
height:36px;
margin-right: 10px;
}
.item-box{
flex:1;
}
.item-title{
font-size:20px;
}
.item-remark{
font-size:14px;
color:#666;
}
.fn-text-overflow {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
效果:
可以看到,当右边的 item-box 中包含其他的子元素时,即使设置了 flex:1,子元素的宽度仍然超出了屏幕,需要在 item-box 上也加上 fn-text-overflow 才能实现省略效果。
html:
<div class="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<img class="item-img" :src="item.imgs" />
<div class="item-box fn-text-overflow">
<div class="item-title fn-text-overflow">{{ item.title }}</div>
<div class="item-remark fn-text-overflow">{{ item.remark }}</div>
</div>
</div>
</div>
效果:
大功告成!
另外,当时在写这个的时候想到了另一种思路,既然 item-box 中不能包含子元素,那把其中的 div 去掉,只展示内容不就可以了?就像下面这样:
html:
<div class="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<img class="item-img" :src="item.imgs" />
<div class="item-box fn-text-overflow">
{{ item.title }} <br> {{ item.remark }}
</div>
</div>
</div>
效果:
新的问题又来了,怎么给右边的两行文字加上不同的样式?
这时候我发现了 display: contents 这个属性。先来看看它的作用吧。
元素本身不产生任何边界框,而元素的子元素与伪元素仍然生成边界框,元素文字照常显示。为了同时照顾边界框与布局,处理这个元素时,要想象这个元素不在元素树型结构里,而只有内容留下。这包括元素在元文档中的子元素与伪元素,比如::before和::after这两个伪元素,如平常一样,前者仍然在元素子元素之前生成,后者在之后生成。
简而言之就是将元素的边界框去掉,元素的背景、边框和填充部分都不会渲染,只渲染元素中的内容,而和内容相关的 color 、font 也能正常生效。
html:
<div class="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<img class="item-img" :src="item.imgs" />
<div class="item-box fn-text-overflow">
<div class="item-title">{{ item.title }}</div>
<br>
<div class="item-remark">{{ item.remark }}</div>
</div>
</div>
</div>
css:
.list-item{
width: 100%;
height:80px;
padding-left: 10px;
padding-right: 10px;
box-sizing: border-box;
display:flex;
align-items: center;
}
.item-img{
width:36px;
height:36px;
margin-right: 10px;
}
.item-box{
flex:1;
}
.item-title{
font-size:20px;
}
.item-remark{
font-size:14px;
color:#666;
}
.item-title,.item-remark{
display: contents;
}
.fn-text-overflow {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
效果:
不过使用这个属性要注意各个浏览器的兼容性问题,比如万恶的IE就不支持这个属性。。。