富文本关键字搜索高亮,解决方法及优化(收藏!)

优采云 发布时间: 2022-07-08 10:01

  富文本关键字搜索高亮,解决方法及优化(收藏!)

  第一版

  首先我们开发一个页面,其中仅包含搜索框和几段富文本的数据

  举个,数据第一项为:

  今天真是个好天气

  这个时候我们想搜索“好天气”,整体的思路是分为3个部分:

  在其中,我们需要记录一些关键状态值:

  type TextToStyleMap = Array<br / {br /  key: span style="color: #c18401;line-height: 26px;"string/span,br /  span style="color: #a0a1a7;font-style: italic;line-height: 26px;"// 从这个字符增加的标签index/spanbr /  up: span style="color: #c18401;line-height: 26px;"number/span[],br /  span style="color: #a0a1a7;font-style: italic;line-height: 26px;"// 从这个字符结束的标签index/spanbr /  down: span style="color: #c18401;line-height: 26px;"number/span[]br / }br /><br />

  让我们简单的画个流程图看一下怎么去做~

  codesandbox.io/s/new-smoke…[1]

  首版完成!(ps:现在我们搜索用的是正则,在大文本的情况下可能会有性能问题

  优化1

  看起来好像很完美了?如果我们在这个文本框中搜索“个好”呢?

  咦,下划线丢了?

  因为我们搜索个好后的富文本结果是

  

  今天真是个好天气

  这里生产出了一个错误的标签不对应的富文本

  我们怎么应对这个问题呢?

  最简单的方式应该是把强调的样式加在每一个文字上

  今天真是个好天气

  ⬇️

  今天真是个好天气

  codesandbox.io/s/upbeat-fe…[2]

  简单的改了一下代码之后,我们就修改了这个bug

  优化2

  这么做了以后,我们会添加许多多余的强调样式标签。比如还是在上面这个例子里,我们如果要搜索『天气』的话,结果会是这样:

  今天真是个好天气

  实际上,天气两个字本身就可以用同一个em标签来包裹,这样可以减少页面中的dom节点树,从而提升性能。

  那么,具体该怎么做呢?这里整体的思路就是原本是在同一个文本段里的文本,我们只用一个em标签包裹,只在出现标签的地方添加额外的命中样式标签。

  这里需要注意的是,添加命中样式标签的时候,需要添加在最内层,也就是命中样式的开标签要放在所有其他开标签之后,而闭标签则要放在所有其他闭标签之前,这样可以保证命中样式的优先级是最高的,不会被其他标签的样式覆盖。

  核心代码逻辑如下:

  const match = [...strs.matchAll(reg)].forEach(({ index }) => {<br /> for (let i = 0; i  0 || // 当有新的开标签时,需要在内部有命中样式的开标签<br />   textToTagMap[letterIndex - 1].down.length > 0 // 当上一个标签有闭标签时,下一个标签需要有命中样式的开标签<br />  ) {<br />   textToTagMap[letterIndex].up.push(emStyleStart);<br />  }<br />  if (<br />   i === word.length - 1 || // 匹配区域结束需要有命中样式的闭标签<br />   textToTagMap[letterIndex].down.length > 0 || // 当有新的闭标签时,需要在内部有命中样式的闭标签<br />   textToTagMap[letterIndex + 1].up.length > 0 // 当下一个标签有开标签时,上一个标签需要有命中样式的闭标签<br />  ) {<br />   textToTagMap[letterIndex].down.unshift(emStyleEnd);<br />  }<br /> }<br />});<br />

  最后的成果✌️

  

  大功告成!

  codesandbox.io/s/restless-…[3]

  结论

  看似完成了?其实还有一些功能没有做,比如局部匹配、多词搜索、emoji匹配等功能,这些就留给大家自己去实现啦

  并且,这里的搜索匹配没有考虑转义字符和不合法标签等问题,实际实现起来也需要多加判断

  刚刚也提到在大文本的情况下使用正则性能会有问题,那是不是可以考虑把textToTagMap换一种数据格式呢?像是字典树之类

  ps:做超大文本量的匹配时也可以选择分片去做,先处理可视区的文字,保证搜索不卡顿

  pss:做富文本相关的内容一定要注意防范XSS攻击哦!

  参考资料[1]

  : %3A%2F%2Fcodesandbox.io%2Fs%2Fnew-smoke-w5hcjv%3Ffile%3D%2Findex.html

  [2]

  : %3A%2F%2Fcodesandbox.io%2Fs%2Fupbeat-feynman-qch060%3Ffile%3D%2Findex.html

  [3]

  : %3A%2F%2Fcodesandbox.io%2Fs%2Frestless-pond-9b14j7%3Ffile%3D%2Findex.html

  最后

  如果你觉得这篇内容对你挺有启发,我想邀请你帮我个小忙:

  点个「喜欢」或「在看」,让更多的人也能看到这篇内容

  我组建了个氛围非常好的前端群,里面有很多前端小伙伴,欢迎加我微信「sherlocked_93」拉你加群,一起交流和学习

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线