解決highlightjs中純文本被解析成HTML無法展示的問題,記一次工作中bug修復的思考


壹 ❀ 引

在本周迭代bug修復工作中,遇到了兩個比較頭疼的bug(同一個客戶所提),bug問題描述也很奇怪,客戶表示產品的富文本編輯器里的代碼塊功能,在純文本語言模式下貼特定代碼進去有的看不見,有的能看見但無法正常編輯,效果如下:

雖然知道了問題的表象,但還是有點無從下手,畢竟這塊的功能不是我做的,實現原理以及功能邏輯都不了解,當然問題到最后肯定還是解決了,不然就不會有這篇文章了,本文也只是記錄從零理解問題以及解決問題的思路。

貳 ❀ 排查思路

前端bug排查其實無非幾個出發點。接口層,bug數據來源接口是否正常,如果不確證直接甩鍋后端同事,此bug直接物理層面被解決。數據層,比如我們公司用的是的react,所以數據檢驗可以通過chrome插件查看component數據以及redux數據是否符合預期。邏輯層,通過讀代碼確認邏輯是否符合功能設計,讀同事的舊代碼往往是一件讓人暴躁的事情,我也如此,實在沒辦法也只能硬着頭皮讀。

但此問題的表現我的第一感覺是出在渲染層面,所以處於驗證,我直接點開了控制台的Elements,也算走運,一看就發現了問題,原來拷貝到代碼塊的代碼並不是未渲染,而是代碼中包含html的標簽直接被解析成了頁面HTML中的一部分,這才導致了不展示以及無法編輯的問題。

客戶拷貝的代碼:

/// <summary>
/// show loading
/// </summary>
public void ShowLoading(){        Controller.instance.StartCoroutine(View.instance.ShowWordWarn(Model.instance.lanDic[55021], 0.2f));
}

控制台展示的結構,summary被解析成了標簽

比較幸運,原本以為是兩個問題,現在只需要解決一個問題了。

叄 ❀ 修復思路

知道了問題所在,接下來需要了解的是富文本編輯器中的代碼塊的功能是如何實現的,簡單看了下代碼,發現實現上依賴了highlightjs,簡單了解了下原理,大概如下:

上圖中表示有兩個視圖層,highlight的code preview也就是三方庫渲染后帶顏色的代碼展示框,而下面還有一個textarer也就是真正記錄用戶輸入以及編輯結果的的編輯框。code preview懸浮在textarea上,再通過樣式定位讓兩個視圖層的代碼對齊,這才有了我們在編輯彩色代碼的效果。

也就是說,highlight渲染的代碼數據其實依賴於textarea的輸入,我們只要在輸入做對應的數據轉化即可。打開chrome,輸入highlightjs html,點擊搜索,然后第一條問題就是我們想要的答案了。highlightjs with html code - Stack Overflow,這種問題咱們肯定不是第一個遇到的,網友絕對不會讓你失望。

解決方案其實也很簡單,比如以下代碼我們不希望被解析html標簽,要做的只是將<>轉義為&lt;&gt;即可。

<p>聽風是風</p>
// 轉為
&lt;p&gt;聽風是風&lt;/p&gt;

代碼塊是支持語言切換的,我們前面說了只有純文本只有這個問題,所以只有當前語言類型是純文本,就需要做標簽轉義,我大概定義了這樣的一個方法:

transformHtmlToText = (code, lang) => {
  return lang === 'PlainText' ? code.replace(/</g, '&lt;').replace(/>/g, '&gt;') : code;
}

如果只是作為展示,這樣貌似也沒什么問題了,取到textarea的值轉義后傳給highlightjs作為展示。但比較尷尬的是,代碼塊是支持用戶操作的,用戶可能會進行代碼編輯或者語言切換,以語言切換為例,假設我們一開始的語言是純文本,且做了轉義:

// 此時語言是純文本
&lt;p&gt;聽風是風&lt;/p&gt;;

現在用戶進行了編輯,刪除了部分代碼,同時把語言切成了java,那么問題來了,用戶編輯刪除時操作的是<p>聽風是風</p>還是&lt;p&gt;聽風是風&lt;/p&gt,切換語言后我是不是應該將&lt;p&gt;聽風是風&lt;/p&gt中的&lt;再反向轉義成<呢?

首先第一個問題我們已經很清楚了,在前面的原理分析中我們已經得知了操作的其實是textarea的值,因此刪除的其實就是textarea的內容,highlight只是對textarea的值在做實時渲染而已。

第二個問題是我們常常會遇到的場景,一個值A因為某個原因被加工成了A+,在經歷了一系列操作后已經變得面目全非,用戶又在某種場景下又需要切回原有的數據A,那么要在A+的基礎上做還原操作嗎?很明顯是不要的。

我在18年就遇到了類似的問題,用戶輸入時需要對文本中相同的文字進行標紅匹配,我在利用正則匹配做了一系列的替換后達到了該效果,現在用戶把輸入的內容刪除了,我當時的第一反應就是對已標紅的文字再做反向還原,但我覺得這太復雜了,數據也極難維護。

當時我同學就說,為什么不把數據當一次性的呢,加工的時候就是一份副本,操作完了自然就遺棄了,你不是本來就有最初的數據嗎,為何要還原呢?

沒錯,在前面的highlight原理分析中,highlight本來就是實時拿textarea的數據,自己進行加工得到了一份彩色代碼的副本,這份副本就是純給我們看的,我們刪除新增代碼時,操作的其實是textarea的值。而我們切換代碼塊語言時textarea的值其實是沒變化的,變化的是highlight需要再拿一次textarea的值按照當前選擇的語言再生產一份對應的彩色代碼而已。

我想表達的大概是下圖這個意思,這是在編程中其實是很重要的一點,保證數據的唯一性,這會讓你的數據變得更可控,在代碼書寫時也會變得相應的簡單。

我在修復此bug的過程中,通過閱讀代碼發現原有邏輯不管是編輯代碼還是切換語言,在對應的監聽方法中都對state的textarea的值,代碼語言類型,以及highlight所需要的值加工都做了實時更新,但我覺得后者值的實時獲取分散在這么多的方法中沒必要的,因為前面說了textarer的值是才是理論上唯一數據源,在state中制好它的更新即可,考慮了一下,我將這些方法中的highlight值操作的代碼都刪除了,並統一到了render中根據textarer與語言類型進行統一加工,bug改了代碼量也相應的減少了一部分,神清氣爽。

那么這大概就是最近一次修bug的經歷,可能是太想寫博客了,所以寫了點東西,那么本文結束。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM