最近在常规迭代中遇到一个很常见,但是经常被我们所忽略的功能 —- 文本过长的展开与收起功能
【前言】工作中会经常涉及到这类型需求,本文从简单的文本省略逐渐进阶过度到展开收起功能实现,可以耐心阅读下去,尽可能讲的有趣一些,如有问题也可以一起交流学习,本人React工作经验很少,目前也在不断学习中,若下面的内容有错误,请各位大佬指正,理性讨论,谢谢☃️
【备注】本文的实现均用 React 实现,各位小伙伴可以采用其他的实现,vue或者纯html都可以,只是方便使用就好,根据自己所需要的业务场景进行更换即可。
【导读】
- 单行文本省略的实现
- 多行文本省略的实现
- 其他方案实现
- 文本展开与收起功能的实现
- 第三方库的应用
- 总结
单行文本省略的实现
关键代码 (css)
white-space: nowrap; // 设置文字在一行显示且不能换行。
overflow: hidden; // 如果文字长度超出限定宽度,则隐藏超出的内容。
text-overflow: ellipsis; // 当文本溢出时,显示省略符号来代表被裁剪的文本。
简单讲解
这种方式很适合需要单行文本所省略的业务场景,几乎不会有什么问题。下面再分析一下优缺点
优点
- 无兼容性问题
- 响应式裁切文本
- 能够限定宽度,显现文本或省略号
缺点
- 仅支持单行文本,不支持多行文本
完整实现
index.jsx
const Index = () => {
return (
<div className="root">
<div className="root-content">
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
</div>
</div>
);
};
export default Index;
index.scss
.root {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
line-height: 1.5;
color: #000;
&-content {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
效果图
多行文本省略的实现
关键代码 (css)
display: -webkit-box; // 弹性伸缩盒子模型
-webkit-box-orient: vertical; // 设置或检索伸缩盒对象的子元素的排列方式
-webkit-line-clamp: 2; // 限制在一个块元素显示的文本的行数,属性值为行数
overflow: hidden; // 如果文字长度超出限定宽度,则隐藏超出的内容。
text-overflow: ellipsis; // 当文本溢出时,显示省略符号来代表被裁剪的文本。
简单讲解
这种方式适合需要多行文本所省略的业务场景,优缺点比较明显,下面进行优缺点分析
优点
- 响应式裁切文本,跟单行文本一样
- 能够限定宽度,显现文本或省略号
缺点
- 兼容性较差,虽然大部分浏览器内核都是 webkit,但是保不准有不是 webkit 内核的浏览器,所以如果需要兼容市场上不是webkit内核浏览器的情况下,不建议采用此方法。
- 容器不能写死高度,需要让容器高度由内容填充,如果写死高度的话会导致显示了省略号但是文本却没有省略的情况发生。
完整实现
index.jsx
const Index = () => {
return (
<div className="root">
<div className="root-content">
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
</div>
</div>
);
};
export default Index;
index.scss
.root {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
line-height: 1.5;
color: #000;
&-content {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
}
}
效果图
其他方案实现
- javascript 实现(计算每行可容纳的字数及行数,来判断是否添加省略号)
- 伪元素 + 定位实现省略 (主要利用定位、行高、固定高度将伪元素定位至文本后达到省略的实现)
还有其他的一些方案,这里不做一一列举,本文重点不在此,感兴趣的小伙伴可以在掘金上搜寻更多的文章去看具体的实现。
文本展开与收起功能的实现
需求解读
终于进入正文,来看看咱们的产品又提出什么需求吧,老规矩,先上图(本处是模拟实际需求时的场景图)。
乍一看,嗯,这不随随便便?把咱们的多行文本省略给朕搬上来一套,代码改都不用改,刚好还是两行的效果,直接上,加个展开功能,完事。
具体实现过程
第一步 (实现多行文本省略)
袖子撸起来,开始照敲刚刚多行文本省略的实现,到这里还是一切顺利的,多行文本也省略了。很好,这就是我想要的效果!!!!我已经离成功进了一大步了(这里代码参照本文多行文本省略的实现,重复内容不重复贴代码)
第二步 (实现展开与收起功能)
脑袋里马上就想到了大概的思路,这点小问题,难不倒我,先获取文本的长度,然后再加一个类名直接去判断显示省略与展示就好。
完整代码
index.jsx
import { useState, useEffect } from "react";
const text = `很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本`;
const Index = () => {
const [show, setShow] = useState(true);
useEffect(() => {
if (text.length > 30) {
setShow(false);
}
}, []);
return (
<div className="root">
<div className={show ? "root-content" : "root-hidden"}>{text}</div>
<span className={show ? "hidden" : "show"} onClick={() => setShow(!show)}>
{show ? "收起" : "展开"}
</span>
</div>
);
};
export default Index;
index.scss
.root {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
line-height: 1.5;
color: #000;
&-hidden {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
}
.show {
color: blue;
cursor: pointer;
&::after {
content: "";
display: inline-block;
width: 0;
height: 0;
border-top: 10px solid blue;
border-right: 6px transparent solid;
border-left: 6px transparent solid;
}
}
.hidden {
color: blue;
cursor: pointer;
&::after {
content: "";
display: inline-block;
width: 0;
height: 0;
border-bottom: 10px solid blue;
border-right: 6px transparent solid;
border-left: 6px transparent solid;
}
}
}
最终效果如下
好!!这时候恭喜您进度已经超过99%了!剩下最后关键的一步!把“展开”与”收起“放在文本的最后
第三步 (实现展开与收起放置文本最后的样式)
完蛋,做到这里的时候突然开始迷茫,不知道该做什么,有点摆烂,css 好像没有尾缩进,不能将最后省略号文本向回缩进,但是还是想到先添加一个float: right;
将展开收起放在右侧,试一试。
做到这里,好像实在没法往下做了,这可能就是css的天花板了,没办法,既然解决不了需求,那就把提出需求的人给解决,马上就跟产品沟通实际效果没办法实现,结果又被打回,接着做,真的是苦了我这个月薪3k5的前端工程师,再薅一下头发,唉。
思考了很久很久,突然脑袋灵光一现,先卖个关子,最后我是怎么实现这个功能的呢?
最终效果图
🤔 好吧,其实就是用了一点点小技巧,不太完美,但可以兼容一些情况,投机取巧把这个需求给完成了
-
先将本来文本省略的方式给去掉,手动加上…(省略号)暂时先不用
-webkit-line-clamp
的方式实现文本省略,转而使用overflow: hidden
实现文本省略 -
确定了使用
overflow: hidden
后,固定line-height: 26px
、确定字号大小font-size: 14px;
(这里可以根据各位小伙伴业务场景进行调整) -
将展开收起的文字放入文本的容器中,利用
position: absolute
定位至文本容器的右下角处right: 0; bottom: 0;
紧接着设定“展开”盒子的宽度,将文本居中放置 -
紧接着设定隐藏盒子的高度
height: 130px
(line-height: 26px;设定大约展示五行),然后给容器外围的盒子调整padding: 10px
-
收起的内容不用动,基本就把整个效果给完成了。
优缺点分析
下面可以分析一下这样的实现方式优缺点
优点:
- 兼容性比较好(不使用
-webkit-line-clamp
) - 也能够响应式去裁剪文本
- 不用使用 javascript 进行计算,纯css实现效果,对性能方面会比较友好
缺点:
- 有细心的小伙伴可能会发现不管怎么调整展开的位置,有时候可能不能完美遮遮挡底部文字,只能根据实际情况进行调整,根据每个字的宽度,大小进行调整,如下图
完整代码
index.jsx
import { useState, useEffect } from "react";
const text = `很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本很多很多文本
很多很多文本很多很多文本很多很多文本很多很多文本很多很多文文多事实上是`;
const Index = () => {
const [show, setShow] = useState(true);
useEffect(() => {
if (text.length > 30) {
setShow(false);
}
}, []);
return (
<div className="root">
<div className={show ? "root-content" : "root-hidden"}>
{text}
<span
className={show ? "hidden" : "show"}
onClick={() => setShow(!show)}
>
{show ? "收起" : "...展开"}
</span>
</div>
</div>
);
};
export default Index;
index.scss
.root {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
line-height: 26px;
color: #000;
font-size: 14px;
padding: 10px;
&-hidden {
position: relative;
height: 130px;
overflow: hidden;
}
.show {
position: absolute;
right: 0;
bottom: 0;
color: blue;
cursor: pointer;
width: 60px;
text-align: center;
background-color: #Fff;
&::after {
content: "";
display: inline-block;
width: 0;
height: 0;
border-top: 10px solid blue;
border-right: 6px transparent solid;
border-left: 6px transparent solid;
}
}
.hidden {
color: blue;
cursor: pointer;
float: right;
&::after {
content: "";
display: inline-block;
width: 0;
height: 0;
border-bottom: 10px solid blue;
border-right: 6px transparent solid;
border-left: 6px transparent solid;
}
}
}
第三方库的应用
其实除了以上的方式之外,可以采用第三方库,已经有大佬造了轮子,可以参考一下@typography-org
,有市面上主流框架的版本,vue、react、native,源码应该是用js进行计算宽度,再将省略号加上,实现展开与收起(个人猜测)。本人暂时还没将其运用至实际业务当中,简单试验了一下,效果还是不错的,希望有使用在实际业务上的小伙伴也能告知一下使用情况。
总结
遇到这类需求,找资料很关键,然后要综合业务场景,拆解需求,一点点向着目标前进,这样子更加容易去实现整体需求。如果对于上面实现方式不满意的话,一点都忍受不了这个瑕疵的话,产品要求一定要完美实现展开与收起功能的话,建议采用第三方库、或者自己手写js代码进行实现。
原文链接:https://juejin.cn/post/7214759986802638908 作者:logg_