浅谈前端高亮文本解决方案

2,812 阅读3分钟

前言

前端实现高亮文本的方法很多,本文主要介绍两种方法:标签式、覆盖式。

本文参考代码点击这里

标签式

标签式

如图所示,标签式主要是通过对高亮的文本添加标签,给标签增加样式实现高亮。

这种方法的难点是:不能简单的通过String.prototype.repeat替换高亮文本,因为在实际开发中,可能我们想高亮的词在页面代码中是有包含有其他标签,或是高亮的文本刚好是一些标签的关键字(a、 span......),这时候repeat便显得比较无力。所以实现关键点是必须在dom树中解析,利用dom的api逐个节点提取节点内容,这样就能避免匹配到html标签。遇到匹配文本跨节点时,我们应该把在各个节点中包含的关键词分别用标签包装起来

跨标签

从上面可以看出,该方案主要可以分为两步:

  1. 解析dom,判断节点内容是否包含需要高亮的文本。

    获取位置

    这里我们主要Node.prototype.textContentString.prototype.indexOf获取关键字所在的文本的位置。

    insertTag

    这里采用递归insertTag不断的查找节点中的需要高亮的内容。

  2. 替换需要高亮的文本节点。

    替换需要高亮文本节点核心是分离原来没有加高亮的标签的文本,这里用的是Text.prototype.splitText方法把原来文本节点中的需要高亮词切分开来。再通过构造包含相同文本的高亮标签替换上。

    切割高亮文本

以上便是标签式高亮的实现方法。

覆盖式

覆盖式

覆盖式就是通过计算出高亮词在页面的的位置,创建出带有高亮的样式的标签覆盖在高亮词的上(下)面。

覆盖式高亮主要的难点:

  1. 如何定位:

    在文字流中定位其实就是确定高亮点的起始点和结束点的位置信息,通过位置信息计算出插入高亮标签的大小和位置。

    循环在每个需要高亮词的前面后面插入Range

    这里通过循环在每个需要高亮词的前面后面插入Range,标记出入高亮词的位置。

    创建Range

    如图所示,通过循环遍历兄弟节点,通过递归查找子节点。

  2. 如何处理高亮词跨行问题:

    多行高亮

    当我们遇到过高亮的文本跨行时该怎么办呢?高亮的区域变成一个不规则的形状,如果小时候搭过积木的话,这个问题就变得简单,像这样的形状我们可以把它看成3块长方形的积木拼接起来,头一行为一块积木,中间若干行(如果有)为另一块积木,剩下的最后一行是一块积木。

    创建多行高亮节点

    使用getBoundingClientRect方法便可计算出高亮长方形的长、宽、横坐标、纵坐标。对比起点和终点的纵坐标便可以得出高亮文本的形状。

总结

最后简单对比一下标签式和覆盖式的特点:

  • 标签式:主要优点是作用于文本中,可以对高亮内容的样式多样化定制,可以跨段落高亮,缺点是插入逻辑复杂,重新高亮文本成本高,顺序定位高亮文本难(上一个高亮文本、下一个高亮文本...)。
  • 覆盖式:主要作用于文本表面,优点忽略dom本身的结构,方便顺序定位高亮文本,容易重新高亮,由于是通过定位覆盖,所以很容易受到外界环境(定位点变化,文本位置变化,行高变化...)的影响,跨段落高亮较难。

文笔粗糙勿喷,如有错误或更多高亮解决方案可以提出来交流,谢谢阅读。