听风是风

学或不学,知识都在那里,只增不减。

导航

解决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的经历,可能是太想写博客了,所以写了点东西,那么本文结束。

posted on 2021-03-15 23:54  听风是风  阅读(1184)  评论(0编辑  收藏  举报