mlellipsis.js-实现多行文字溢出隐藏显示省略号
超出容器部分文字做省略,这是基本写前端代码都会遇到的问题。某些位置为了表现完美不额外加滚动条,都会要求多出的部分作省略,例如文章简介”今天天气真的好…”,文本之后部分点击进入详情页才能看到,超出多余的用”…”省略。然而,一般这些简介都是用后台语言去作处理,例如只显示前140字等,如何用前端代码实现?你会想到用css的overflow:hidden;white-space:nowra
超出容器部分文字做省略,这是基本写前端代码都会遇到的问题。
某些位置为了表现完美不额外加滚动条,都会要求多出的部分作省略,例如文章简介”今天天气真的好…”,文本之后部分点击进入详情页才能看到,超出多余的用”…”省略。
然而,一般这些简介都是用后台语言去作处理,例如只显示前140字等,如何用前端代码实现?
你会想到用css的overflow:hidden;white-space:nowrap;text-overflow:ellipsis实现省略,然而这只能省略一行的文字,如果多行文字则失效,应该如何解决?
在新版的chrome中有一个属性-webkit-line-camp属性,它允许你指定特定行数省略。
例如:3行后省略
1 | text- overflow :ellipsis; |
2 |
3 | display :-webkit-box; |
4 |
5 | -webkit-line-clamp: 3 ; |
6 |
7 | -webkit-box-orient:vertical; |
另外,在opera中也有相关的支持属性text-overflow:-o-ellipsis-lastline,他能识别超出容器的最后一行作省略,然而明显地,chrome的做法更优雅,更灵活。
可是,以上都是个别浏览器的实现,想要各种浏览器(包括IE哥哥)都用上,怎么办?
于是我就写了这个东西:mlellipsis.js
先猛戳我这个简陋的demo,调用方法其实很简单:
1 | element.mlellipsis(5); //element即dom元素 |
其中,5是行数,也就是和chrome的-webkit-line-clamp实现方式一样,指定特定行数显示;
若用jquery的朋友,可以在获取元素后把它转化为js的dom对象。
例如:
1 | var node = $( ".demo > [" )[0]; |
2 |
3 | node.mlellipsis(5); |
具体做法如下:
1 获取该调用node结点的文字大小、行高、文本的高度;
2 根据行高*想要省略的行数row,判断文本的高度是否大于需要省略的高度,如果大于则不需要隐藏(例如字数一行就能显示,那么输入row=2也只会显示一行);
3 因为会省略文字,所以先把完整文字内容写入标签的title属性,hover后可以查看全部原文本;
4 动态截断文本后面的文字,并加上”…”,直到截断后的文字高度和目标的高度一样,则不拦截;
逐步分析:
1.获取计算后属性
首先获取node节点的三个值会涉及到浏览器的兼容性,例如一般现代浏览器可用新属性getComputedStyle获取计算后的css属性,而可爱的IE6-8不支持这个属性,需要用this.currentStyle。
「ps:具体差别可点击这里参看zxx对getComputedStyle介绍的文章」
其实如果用jquery的话可以直接调用css()方法获取,然而懒得加载jquery,因此我重写了一次。
01 | Element.prototype.getFinalStyle= function (property){ |
02 | var s; |
03 | if (window.getComputedStyle){ |
04 | s = window.getComputedStyle( this , null )[property]; |
05 | } |
06 | else { |
07 | s = this .currentStyle.property; |
08 | } |
09 | return s.substring(0,s.length-2); //减去元素的单位px |
10 | } |
因此,获取元素属性的就很简单了:
1 | //获取计算后的样式 |
2 | var fontSize = this .getFinalStyle( "fontSize" ); |
3 | var lineHeight = this .getFinalStyle( "lineHeight" ); |
4 | var height = this .getFinalStyle( "height" ); |
注意了,我重写的这个只为了适这个js,因此其他的属性可能不支持,例如没有px或者单位不为px的属性值。
//路人甲:把s.substring()不写进去就行了嘛,那就可以兼容了
//tq:我就是懒……
然而,这里我还发现了一个问题,就是line-height值,一般如果不设置line-height会是什么值?1.5么?
非也,会是获得”normal”的一个string类型,我再找了一下资料{资料1,资料2}发现normal是个神奇的数值,不同浏览器、不同字体、不同系统都会有各自的解析!
//tq:omg…那怎么办
是的,我们要获取正确的高度,就一定要获得精确地line-height值。因此我看了各个line-height的大致比例,我决定把它reset掉,就是如果line-height为normal,则我把line-height设为1.5,即1.5倍的font-size;
2.获取内容文本
无独有偶,获取文本的时候也会遇到浏览器兼容的问题,除了firefox外,其他浏览器都能支持innerText属性,因此直接调用this.innerText木有问题,然而ff的innerText却为undefined,但它却用textContent可以实现相同效果。具体差别点击这里。
你懂的,我继续重写:
1 | Element.prototype.getText= function (){ |
2 | if ( this .innerText){ return this .innerText;} |
3 | else { return this .textContent;} |
4 | } |
5 |
6 | Element.prototype.setText= function (str){ |
7 | if ( this .innerText!= "" ){ this .innerText=str|| "" ;} |
8 | else { this .textContent=str|| "" ;} |
9 | } |
调用方法就简单地this.getText()即可或者this.setText(“str”)改变其值
3.设置title值
这个很简单
1 | var str = this .getText(); |
2 | this .setAttribute( "title" ,str); |
4.关键步骤:动态截取文本
这里用了正则,匹配当文本高度小于目标高度(省略行数x行高=元素省略时该显示的目标高度)时,不断截取后面的文本,并加上”…”省略号。
01 | //减去末尾文字 |
02 | while (dheight< this .clientHeight){ |
03 | str = this .getText(); |
04 | this .setText(str.replace(/(\s)*([a-zA-Z0-9]+|\W)(\.\.\.)?$/, "..." )); |
05 | } |
06 |
07 | /* |
08 | * /(\s)*([a-zA-Z0-9]+|\W)(\.\.\.)?$/ 正则解析: |
09 | * (\s)* 0或多个空白 |
10 | * ([a-zA-Z0-9]+|\W) 一个或多个字母数字 或 任意不是字母,数字,汉字的字符 |
11 | * (\.\.\.)? 零个或一个... |
12 | */ |
5.简单剪枝
看似结束了,但是如果文本有8000+,但是只需要显示前几行,则只显示100+字呢?
那会由于需要不断截取字符,循环会疯掉。用chrome的调试行数console.time()和console.endTime()测试后发现,如果不优化直接上的话8800字需要17s!
然而这里只需要简单剪枝,就可以保持无论多少文字都几十ms的水平了。
剪枝思考:初步打算用二分法,就是当文本高度大于目标高度2倍,则截断一半文字。然而,再考虑到文本里分为三种:中文字、英文字、字符;一般来说,中文字=2英文字=2字符。因此最坏情况可能前面一半字符全部是英文,后面一半文本全部是中文,这样二分法就会截取到25%的高度,因此考虑到最坏情况,需要3倍才截断。
1 | while (dheight*3< this .getFinalStyle( "height" )){ |
2 | this .setText(str.substring(0,str.length/2)); |
3 | str = this .getText(); |
4 | } |
这里剪枝还可以大大优化,欢迎提出宝贵意见~*_*
以上,兼容到IE8+,chrome,firefox,safari,opera。
IE7以下不支持element.prototype的原型链扩展,果断鄙视之。
下载:
mlellipsis.js(完整版带注释:1.70k)
mlellipsis.min.js(压缩版:1.06k)
出处targetkiller 原文点此 http://targetkiller.net/mutiple-line-ellipsis/
更多推荐
所有评论(0)