常规业务需求中大前端的工作者应该都遇到过类似需求,固定展示 N 行,句末显示 展开 ,点击展示 全部 ,可进行 收起 操作。
目标
方案
纯CSS方案
- 1.先实现第一步达到行数要求时显示....,这个不多赘述
<div class="desc">
沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我
是落叶落寞又落魄,看我残留的热情,穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
.desc {
display: -webkit-box;
-webkit-line-clamp: 3; // 文本展示最大的行数
-webkit-box-orient: vertical;
overflow: hidden;
text-align: justify;
font-size: 16px;
line-height: 44px;
}
- 2.显示展开/收起按钮
<div class="desc">
<button class="btn">展开</button>
沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我
是落叶落寞又落魄,看我残留的热情,穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
.btn {
float: right;
clear: both;
background-color: #f00;
border: none;
color: #fff;
line-height: 24px;
}
.desc {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-align: justify;
font-size: 16px;
line-height: 44px;
}
利用float 浮动,让按钮进入文本环绕式布局,但此时我们可以看到,按钮显示的位置为右上角,与需求有出入,如何让他下来呢,可利用的样式 padding margin,布局边界,优先采用margin,看下效果
按钮移动到右下角,但文本的环绕模式并没有保留,文字渲染区域被切割。margin无法满足,因为文档中上方的空间依然被按钮所占据,而按钮元素并没有脱离文档流,自然文字无法进行空白区域的二次渲染。
- 3.保留浮动布局,让按钮移动下来,增加一个元素把按钮挤下来
.btn { float: right; clear: both; // 清除浮动 background-color: #f00; border: none; color: #fff; line-height: 24px; } .desc { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; text-align: justify; font-size: 16px; position: relative; line-height: 44px; } .desc::before{ content: ''; float: right; width: 10px; height: 46px; background: #000; overflow: hidden; }
- 4.隐藏模式利用伪类,达成UI还原度
.desc::before{ content: ''; float: right; width: 0px; height: 46px; overflow: hidden; }
- 5.当文本行数不出现溢出是,按钮无法自动隐藏 看效果
解决方案:类上,采用伪类遮盖的方式障眼法
.desc::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: #000;
}
绝对定位,不设置 left top bottom right; left top 会默认进入文档流
优化:伪类背景色与大背景颜色一致,即可解决问题了
- 6.检查配置,提高复用性
// desc::before 的高度严格依赖了字体行高,这相当于写死的配置,复用性太差。
// height 相当于元素100% - 按钮的高度 - (行高-按钮高)/2
// 自然想到一个属性 calc(100%- 34px)
// 会发现height :100% 在标准文档流里面是获取不到的。 可通过flex 布局打破
修改元素节点,增加负类元素
<div class="content">
<div class="desc">
<button class="btn">展开</button>
沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我,是落叶落寞又落魄,看我残留的热情
穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
</div>
.content{
display: flex;
overflow: hidden;
}
这时候就可以正确获取元素height,因为calc 存在兼容性,更好的方案应该是
height: 100% margin-bottom:-34px
性能也更加友好
- 7.完整实现代码
.content{
display: flex;
overflow: hidden;
}
.btn {
float: right;
clear: both;
background-color: #f00;
border: none;
color: #fff;
line-height: 24px;
}
.desc {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-align: justify;
font-size: 16px;
position: relative;
line-height: 44px;
word-break: break-all;
}
.desc::before{
content: '';
float: right;
width: 0px;
/* height: calc(100% - 32px); */
background: #000;
overflow: hidden;
height: 100%;
margin-bottom: -34px;
/* 性能更好,兼容性更好 (line-height - btn height)/2 + btn height */
}
.desc::after {
content: '';
position: absolute;
width: 100%;
height: 100px;
background: #fff;
}
<div class="content">
<div class="desc">
<button class="btn">展开</button>
沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我,是落叶落寞又落魄,看我残留的热情
穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
</div>
下沉为业务基础组件,完全的灵活性,分析以上代码中的样式表
文本行高,采用js 获取 document.defaultView.getComputedStyle(el)["line-height"]
按钮的行高直接继承
JS 实现方案
let el = this.$el;
let lineHeight = parseFloat(
document.defaultView
.getComputedStyle(el)
["line-height"].replace("px", "")
);
let COMPAT_VALUE = 10; // 取 10 作为一个缓冲值,防止不同浏览器展示的高度不同
if (el.offsetHeight > lineHeight * this.maxLine + COMPAT_VALUE) {
// 超出最大行,需要折叠操作
this.foldState = FOLDED;
// 延迟一下让 展开的按钮可以更新到页面上
this.$nextTick(_ => {
while (el.offsetHeight > lineHeight * this.maxLine + COMPAT_VALUE) {
// 为了处理 emoji 的删除, refer to http://www.alloyteam.com/2016/12/javascript-has-a-unicode-sinkhole/
let tmpArray = Array.from(this.textEl.textContent);
tmpArray.pop();
this.textEl.textContent = tmpArray.join("");
// console.log(this.textEl.textContent, el.offsetHeight)
}
});
}
实现思想: 把需要展示的按钮 省略号全部丢到 父类dom 元素中,通过循环计算 实际渲染的高度与 可展示的最大高度比较,对文本内容进行减法运算。实现最终高度一致
####### 参考: