IM應用中如何計算富文本的高度

背景

在開發IM的項目過程中,經常會有出現一些需要計算DOM高度,然后超出若干行隱藏等需求。很多時候,需要計算高度的DOM元素都是動態生成的,我們無法在數據渲染前獲取到它的高度。

如果沒有任何交互,我們可以通過CSS來實現這個需求。但是,如果我們需要使用JavaScript來實現一些交互(比如消息渲染時,超過2行顯示某個特定按鈕等),則只能通過JavaScript來進行實現。我在這里介紹一種通過JavaScript來對元素高度進行計算的方法,希望能夠給大家提供一些思路。

技術方案

根據前端的基本常識,在內存中未渲染的DOM元素是無法獲取到高度的,因此我們有兩個方向來解決這個難題:

  1. 通過字數對行數進行估算。
  2. 將元素渲染后進行高度測算 。

實現方案

以下的實現方案將根據上面所選擇的技術方案來進行實現。

通過字數進行估算

方案

此方案無需多言,就是通過字的總數、行高和每一行能夠容下的字的個數進行估算等。在項目最開始時,我采用的就是這個方案。具體實現代碼較為簡單,因此不在本文中提供示例。

優點

此方案實現簡單,基本不需要任何技術成本。

缺點

只適用于等寬文字,如果出現富文本(比如有emoji或者圖片表情等高度不一致)的情況,則無法適用。如果字體為非等寬字體或者存在\n之類的換行符或者是\t之類的制表符時,估算的準確度也會下降。

在DOM渲染后進行操作

方案

顧名思義,此方案就是先不考慮DOM元素行數邏輯,直接將所有的DOM節點全部渲染到頁面中,渲染完成后再對進行后續邏輯判斷。獲取高度后頁面行數計算將在后面統一講解。

優點

此方案通過直接在實際場景的頁面上渲染后進行高度計算,因此計算精準,不存在任何偏差。同時,此方案實現起來也較為簡單,只需要將業務邏輯執行時間后延,并不需要開發額外的代碼。

缺點

該方案缺點也比較明顯,由于是先渲染后處理,因此頁面DOM元素會出現重繪和重排,導致頁面閃動,從而影響用戶的體驗。

鏡像計算

方案

該方案的靈感來自于上一個方案。因為在實際的頁面中進行計算能夠保證頁面高度計算沒有任何誤差,因此我們需要一個實際的場景,讓瀏覽器來幫助我們進行高度計算。同時,我們又不能在具體的功能頁面中先渲染后計算,因此我們可以直接創建一個與實際頁面中一模一樣的容器來進行高度計算。這樣我們既能夠精確計算,又能夠不影響用戶體驗。

具體實現的代碼可以參考如下示例:

export default function getLines(element = 'div', style = {}, html = '') {let node = document.createElement(element);//創建一個新容器let length;each(style, (element, index) => {node.style[index] = element;//將傳入的style遍歷后賦值給新容器});node.innerHTML = html;document.body.appendChild(node);//需要將新容器掛載到DOM中,瀏覽器才會進行高度計算let height = global.getComputedStyle(node).height;document.body.removeChild(node);//需要將鏡像DOM進行移除if (height.indexOf('px') > 0) {length = parseInt(height.split('px')[0]);} else {length = 0;}return length;
}
復制代碼

優點

該方案基本上繼承了第二個方案的所有優點——精確計算,無誤差,并且避免了出現頁面閃動的情況。

缺點

此方案仍然存在一些問題,將新容器掛載到document元素上時,可能會引發DOM元素的重新渲染,極低概率會影響頁面布局。同時,屬性值等需要自己手動傳入,而不是利用現成的容器,比較費時費力。

方案再優化

利用現有DOM容器

使用cloneNode方法來對現有的容器進行clone,我們可以省去輸入樣式的麻煩,同時能夠精確保證兩個容器完全一致。

隱藏鏡像DOM

在實踐過程中,在append以后立刻remove鏡像DOM節點,不會對頁面產生任何影響。如果擔心添加時會給頁面造成閃動效果,可以給鏡像DOM添加上position:fixed;visibility:hidden;z-index:-999;屬性,能夠讓鏡像DOM在append到頁面時,不會影響當前頁面的任何布局。

為什么我們不使用display:none來實現上述效果呢?因為在使用了該屬性后,window.getComputedStyle獲取的高度將變為auto。同理,如果元素的display屬性為inline時,也會出現類似的效果,因此我們需要將display指定為block或者inline-block

理論上我們的容器都應該為塊級元素,否則計算高度的意義也就不存在了。因此在容器clone時只需要留意即可,不需要重新指定。

兩個優化點經過實踐已經證明可行,具體代碼就不附上了,如果有需要的可以給我留言~~

通過高度來計算行數

目前,通過高度來計算行數并沒有什么比較好的方法,一般是通過line-height兩個屬性來進行計算。

如果line-height為倍數的話,則還需要font-size屬性來確定具體高度。

具體算法為:總高度 / 每一行高度 = 行數

而每一行高度則通過line-height或者line-height* font-size確定。

總結

獲取動態元素的高度一直都是IM項目中的一個重要需求,自己在這個方面也踩了許多坑,因此寫了這一篇博客來進行記錄,同時其他人如果看到了也可以避免一些常見問題。

由于此方案較為繁瑣,同時容易留下不少坑,不太推薦使用此方法,還是建議通過產品方案等其他手段規避此方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254716.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254716.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254716.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

G代碼 機器人的CNC實現

  控制銑削工作臺和工件的NC程序,通過CAD軟件創建,這些NC程序與特定的機器類型相關。 NC程序在笛卡爾坐標系中動作的描述,對于需要確保一個明確的變換軸位置的關節型的機器人來說,缺少附加的狀態和旋轉信息。傳…

IScroll5中文API整理,用法與參考

IScroll是移動頁面上被使用的一款仿系統滾動插件。IScroll5相對于之前的IScroll4改進了許多,使得大家可以更方便的定制所需的功能了。 做項目的時候正好用到了這個插件,自己做了一下總結,發在這里方便大家學習IScroll5。 官網:htt…

Linux?安裝USB攝像頭

sudo apt-get updatesudo apt-get install fswebcamsudo apt-get install mplayersudo apt-get install alsamixer安裝完畢ls /dev查找設備是否有video0這個設備sudo mplayer tv:// 可以看到攝像內容轉載于:https://www.cnblogs.com/smartkeke/p/6820426.html

struct x264_t 維護著CODEC的諸多重要信息

//x264_t結構體維護著CODEC的諸多重要信息struct x264_t{/* encoder parameters ( 編碼器參數 )*/x264_param_t param;x264_t *thread[X264_SLICE_MAX];/* bitstream output ( 字節流輸出 ) */struct{int i_nal;x264_nal_t nal[X264_NAL_MAX];int i_bitstr…

如何判斷一條曲線是否自己相交?

今天看到群里有人在問這個問題,想了一個解決辦法。 我們首先作假設,如果一條曲線有交點,那么它就是相交的對吧。可能大家想的都是這樣,就開始找各種方法去識別交點。 我們換個角度想一下:是不是我們判斷這條曲線是否帶…

XML 與網絡的數據傳輸

XML 與網絡的數據傳輸

hdu 5813 Elegant Construction

水題 題意:有n個城市,給你每個城市能到達城市的數量,要你構圖,輸出有向邊,要求無環,輸出任意的解 例: Sample Input 332 1 021 143 1 1 0Sample OutputCase #1: Yes21 22 3Case #2: NoCase #3: …

Redis實戰筆記

Redis 數據庫 一、 概要 1. 特點 用于抽象數據類型的 DSL內存存儲基礎數據結構 API編碼風格避免代碼復雜兩層 API以優化為樂2. 數據類型 鍵值對(字符串->字符串)哈希列表(鏈表)集合:差并交有序集合 列表 集合位圖…

內存申請與一級二級指針

1.如果是函數內進行內存申請,很簡單,標準用法就可以了: test(){int *array;array(int *)malloc(sizeof(int)*10);//申請10*4 bytes,即10個單位的int內存單元}注意,malloc使用簡單,但是注意參數和返回值&…

halcon相機標定及圖像矯正(代碼)

侵刪 1 halcon相機標定和圖像矯正 對于相機采集的圖片,會由于相機本身和透鏡的影響產生形變,通常需要對相機進行標定,獲取相機的內參或內外參,然后矯正其畸變。相機畸變主要分為徑向畸變和切向畸變,其中徑向畸變是由透…

找尋一個郵箱

import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern;public class zhengze {public static void main(String[] args) { //1.創建一個正則表達式對象Pattern pPattern.compile("[0-9]{6}"); //2.獲得匹配器 String s…

先弄個XML解析器代碼抄一抄 慢慢研究 O(∩_∩)O哈哈~

出處:http://bbs.csdn.net/topics/390229172 已經自我放逐好幾年了.打算去上班得了.在最后的自由日子里,做點有意義的事吧... 先來下載地址 http://www.kuaipan.cn/file/id_12470514853353274.htm 已經在很多正式,非正式的場合…

紫書 例題8-10 UVa 714 (二分答案)

這道題讓最大值最小, 顯然是二分答案當題目求的是最大值最小, 最小值最大, 這個時候就要想到二分答案為什么可以二分答案呢, 因為這個時候解是單調性的, 如果簡單粗暴一點就全部枚舉一遍, 驗證答案。但是因…

was not declared in this scope

“was not declared in this scope”是一個錯誤信息,在編譯的時候會遇到。其含義為標識符在其出現的地方是未被定義的。 出現該錯誤的時候,會同時把未定義的變量名顯示出來。比如如下程序: int main(){ printf("%d",i);//這個i是…

函數參數的傳遞問題(一級指針和二級指針)

函數參數的傳遞問題(一級指針和二級指針) [轉]原以為自己對指針掌握了,卻還是對這個問題不太明白。請教! 程序1: void myMalloc(char *s) //我想在函數中分配內存,再返回 { s(char *) malloc(100); } void …

Win7下使用U盤安裝linux Ubuntu16.04雙系統圖文教程

Win7下使用U盤安裝linux Ubuntu16.04雙系統圖文教程 Ubuntu(友幫拓、優般圖、烏班圖)是一個以桌面應用為主的開源GNU/Linux操作系統,Ubuntu 是基于DebianGNU/Linux,支持x86、amd64(即x64)和ppc架構&#xf…

SynchronizationContext

SendOrPostCallback xxx vg > { Text "內部: "vg.ToString(); };dynamic vx new { a SynchronizationContext.Current, b xxx };Thread td new Thread(x >{dynamic tmp x;// SynchronizationContext ds x as SynchronizationContext;for (in…

CoDeSys的前世今生

工作以及網上看到不少人說,CoDeSys和西門子step7,在德國都屬于標準過程,牛逼的小朋友都可以用其編程,不知真假,相信無風不起浪,多少有些依據,看看國內清一色的日系編程…

UVALive 7324 ASCII Addition (模擬)

ASCII Addition題目鏈接: http://acm.hust.edu.cn/vjudge/contest/127407#problem/A Description Nowadays, there are smartphone applications that instantly translate text and even solve math problems if you just point your phone’s camera at them. You…

Eclipse中執行Ant腳本出現Could not find the main class的問題及解

試過了:https://blog.csdn.net/bookroader/article/details/2300337 但是不管用,偶然看到這篇沒有直接關系的 https://blog.csdn.net/jiuyueguang/article/details/9350753 聯想了一下。項目是JDK1.5,Eclipse是JDK1.8啟動,所以在R…