文本截断知多少

文本截断是咱们前端常常会碰到的需求,有些文本比较长,设计师每每会在有限的空间内限制字符数量,以确保界面的美观性,并且会在一些字符后面加上省略号来表示截断,这个时候咱们每每会使用css3的text-overflow:ellipisis来解决,单行文本截断没什么问题,多行文本咱们也能够借助webkit的私有属性**-webkit-line-clamp**来解决。可是这是一个不规范的属性,并无出如今CSS规范草案中,因此只能在webkit内核的浏览器下使用。今天介绍一下如何使用javascript来实现文本截断,并附上一个基于vue的文本截断组件ellipisis-plusjavascript

原理

相信你们很容易就会想到如何实现,就是计算、计算、计算。不过我仍是先把原理啰嗦出来,以避免有些童鞋一时想不到。 简单来讲,文本截断的实现就是依赖一个简单的数学公式。Y*L=n*X+Dcss

  • Y表明容器宽度。✅

容器宽度很容易计算出来,用offsetWidth。html

  • L表明显示行数。✅

显示行数由于是咱们指定的值,因此也是已知量。前端

  • n表明字符个数。❓

待求。vue

  • X表明字符宽度。❌

字符宽度,这个就不太统一了,为何呢?首先,假定咱们* 字体大小*、字体类型 设置统一的状况下,浏览器对英文字母、数字、特殊符号、汉字等渲染的宽度都是不一样的。即便英文字母,不一样字母的宽度也是不尽相同的。因此,字符宽度咱们没法肯定。java

  • D表明省略号占位符的宽度。✅

能够利用offsetWidth计算得知。css3

咱们要求解的是字符个数n,因此,容器宽度、字符宽度、显示行数、省略号占位符宽度 这四个参数必须是肯定的。千言万语抵不过一张图。git

由于字符宽度X不肯定,因此单纯依赖这个公式,咱们没法计算出字符个数。你也许会说了,前面你不是已经说依赖这个数学公式吗?如今又说这个公式没法计算出字符个数,这不自相矛盾吗?github

是的,没错。单单依靠这个公式是没法达到咱们的目的,可是咱们若是想达到截断的目的,仍是须要这个公式来支撑的。也就是说,这个公式是实现文本截断的一个必要条件,咱们还须要其余手段,并结合这个数学公式来实现。web

好吧,从新整理一下咱们的思路。为了达到文本截断的目的,咱们须要找到一个临界字符,这个字符可以恰好显示在指定行的末尾。

临界字符是这样的一个字符,紧跟它的字符一旦添加到容器中,容器就会另起一行显示。

那么问题来了,如何找到这个临界字符呢?聪明的你也许已经想到了,咱们能够一个一个的添加字符,每添加一个字符就检查一下容器的高度是否超过指定行的高度,以下动图。

咱们一个个的往容器中添加字符,每添加一个,就检查一下容器的高度是否超过指定行的高度。若是恰好超过,那么当前字符就是咱们的临界字符,这个方案没问题,妥妥哒,演示地址。接下来,咱们看下这个方案中的细节。

细节

上述方案大方向没问题,可是有些细节要注意。

**1. 性能 **

首当其冲的是性能问题,咱们不难想到,在咱们每次添加一个字符的时候,都要从新计算容器高度,而容器高度是经过offsetHeight计算得来的,咱们都知道offsetHeight一旦调用,就会强制浏览器重排(reflow),次数多了,天然会影响性能。因此咱们要作点小优化。什么优化呢?咱们的公式Y*L=n*X+D派上用场了。

  • 咱们能够假定全部字符都是中文字符,计算单个中文字符的宽度缓存起来,而后经过这个公式计算一个估值L,咱们截取前L个字符,放到容器中。
  • 判断当前容器高度是否大于指定高度。
    • 若是大于指定高度,说明咱们的L值取大了,须要往少了减小字符去探测。
    • 若是小于指定高度,说明咱们的L值取小了,须要往多了增长字符去探测。

经过这个手段,咱们能够大大下降浏览器的重排引发的性能问题。

2. 字符宽度的计算

再说下字符宽度,字符宽度并非和字体大小等大的,字符宽度除了和语言符号有关,还和样式有关,好比font-size,letter-spacing等。因此咱们在计算的时候,要将单个字符放到一个内联容器中,经过容器的offsetWidth来计算。即使咱们经过offsetWidth来计算,也仍然要注意如下两点:

  • 首先字符的宽度不必定都是整数,也有多是浮点数,好比英文字母,特殊符号等。
  • 其次offsetWidth会根据字符宽度四舍五入来取整,因此致使咱们计算出来的实际宽度不许,这个时候咱们必须向上取整,以保证字符总宽度小于等于容器宽度和行数的乘积。不然,咱们的临界字符会取的不许。

3. 容器宽度的计算 如第二条所说,offsetWidth会根据宽度四舍五入来取整,因此咱们的容器宽度也未必是准的,这个时候,咱们要对容器宽度向下取整,目的也是为了让字符总宽度小于等于容器宽度和行数的乘积。

也许你会说咱们能够用getComputedStyle来计算宽度,很不幸的告诉你,经过这种方式计算出的容器宽度并不老是数值,也有多是"auto"。

4. 容器每行字符所占高度的计算 容器每行字符所占高度与font-family、font-size、line-height有关,以下图所示,不一样的字体,同时设置100px字体大小,line-height设置为1,字符所占空间的高度是不一样的,更深层次的缘由请戳这里

因此咱们没法经过这三个要素来精确计算容器每行字符的高度。但有一个取巧的手段:为容器添加一个字符,计算容器的offsetHeight得出行高。

总结

由文本截断咱们能够总结一些知识点:

1. offsetWidth获取的数值不可靠。

2. 字符所占空间的宽度、高度和字体、字号、行高等综合影响有关。

3. getComputedStyle计算出的宽度、行高并不老是数值。

源码

说了这么多理论的东西,也是时候来点源码了,我就不贴了,具体请戳这里。查看演示请戳这里

相关文章
相关标签/搜索