關於帶有"顯示更多"按鈕的多行文本截斷思考

恰好最近遇到這個小需求,記得很早以前都是用JS處理,畢竟那時候年少無知。切換類的操做能夠用Checked僞類實現,成本會比較低一點,那麼先來列一下功能要點:前端

  1. 多行文本截斷,顯示省略號
  2. "顯示更多"按鈕能夠展開全部文本
  3. 展開文本後,按鈕的文字變成"收起文本"
  4. 按鈕的出現條件爲當文本被截斷時(若是你文本只有一行,那就不必顯示了吧😓)

疑問點:text-overflow: ellipsis不支持多行截斷。按鈕文字切換,CSS該如何切換文本? 按鈕的出現條件又如何判斷? 下面我將逐一講解🎈web

多行文本截斷

假設現有的HTML結構以下:微信

<div class="box">
  <p>文本內容</p>
</div>

若是須要單行截斷,通常的作法是:學習

p {
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

效果以下:
spa

多行文本須要用到line-clamp,定義被截斷文本的行數:3d

p {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

效果以下:
code

按鈕點擊展現全部文本

如今HTML結構改形成以下:cdn

<div class="box">
  <input type="checkbox" name="toggle" id="toggle" style="display: none;">
  <p>文本內容</p>
  <label for="toggle">顯示更多</label>
</div>

監聽按鈕的點擊行爲則用文首說的Checked僞類:server

input[name="toggle"]:checked {
 & + p {
   -webkit-line-clamp: unset;
 }
}

這樣當用戶點擊(選中)的時候,將展現全部文本,未選中則收起文本:
blog

按鈕文字動態化

講道理,當展現全部文本以後,按鈕的文字應該要切換成"收起文本"CSS怎麼修改文本啊,其實用僞元素的content就好了。

HTML中的文字去掉,而後換成CSS控制:

<label for="toggle"></label>

label {
  &::after {
    content: "顯示更多";
  }
}

同理可得:

input[name="toggle"]:checked {
  & ~ label {
    &::after {
      content: "收起文本";
    }
  }
}

效果以下:

按鈕樣式醜的那就本身調一下咯😓

按鈕出現的條件

當文本少於三行時,按鈕不該該出現,由於不必:

出大問題,網上衝浪後,發現沒有任何僞類能夠判斷文本是否被截斷,若是有,咱們能夠這樣作:

p {
 &:truncated {
   & + label {
    display: block;
   }
 }   
}

label {
  display: none;
}

truncated意思是截斷的。

不過就算這樣,也沒法實現咱們的需求,由於當你顯示全部文本後,你的文本就沒有被截斷了,因此按鈕會消失:

以上是依靠一段JS實現的模擬效果,源碼以下:

let list = document.querySelectorAll("p");
let observer = new ResizeObserver(entries => {
  entries.forEach(item => {
    item.target.classList[item.target.scrollHeight > item.contentRect.height ? "add" : "remove"]("truncated");
  });
});

list.forEach(p => {
  observer.observe(p);
});

原理就是監聽文本元素的大小變化,而後動態增長truncated類名😂

因此,你的CSS中的truncated僞類應該改爲truncated類😓

p {
 &.truncated {
   & + label {
    display: block;
   }
 }   
}

咱們但願切換的時候,按鈕一直都在,而不是文本沒被截斷的時候就不顯示按鈕,所以,咱們不須要一直監聽文本元素的大小改變,咱們只須要一個初始值(文本初始化的時候到底有沒有被截斷),也就是隻監聽一次!

entries.forEach(item => {
  //... 原來的代碼
  
  observer.unobserve(item.target); // 移除監聽
});

或者根本不須要用這個API,直接頁面初始化的時候,遍歷判斷一遍就行拉!

let list = document.querySelectorAll("p");

list.forEach(item => {
  item.classList[item.scrollHeight > item.offsetHeight ? "add" : "remove"]("truncated");
});

這樣,P元素在頁面初始化的時候,會自動加上truncated類名,而按鈕又能夠一直顯示:

擴展

好比你能夠自定義按鈕樣式、在底部增長一個透明漸變的蒙層、切換時候的過渡效果😁

總結

checked僞類是個好東西,能知足不少需求而不用寫JS,所以凡有關切換類的操做均可以考慮用它。若是你以爲這篇文章不錯,請別忘記點個關注哦~😊

交流

微信公衆號「前端宇宙情報局」,將不定時更新最新、實用的前端技巧/技術性文章,對了偶爾還會有互聯網中的趣事趣聞🍻

關注公衆號,回覆"1"獲取羣聊二維碼,一塊兒學習、一塊兒交流、一塊兒摸魚🌊

相關文章
相關標籤/搜索