文本截斷知多少

文本截斷是咱們前端常常會碰到的需求,有些文本比較長,設計師每每會在有限的空間內限制字符數量,以確保界面的美觀性,並且會在一些字符後面加上省略號來表示截斷,這個時候咱們每每會使用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計算出的寬度、行高並不老是數值。

源碼

說了這麼多理論的東西,也是時候來點源碼了,我就不貼了,具體請戳這裏。查看演示請戳這裏

相關文章
相關標籤/搜索