前端实现基于后端返回的文档内容关键字搜索高亮

需求背景及技术实现

针对上传的word文档实现关键字搜索高亮 且需要通过向上向下查找按钮实现当前关键字位置高亮颜色不一样
后端返回文档的html内容
前端实现文档搜索关键字高亮 –>前端查找文档存在的关键字提取创建font标签包裹关键字并加上样式后放到原位置,开发自提优化屏幕滚动到当前高亮关键字的位置

注意点

1、关键字可能分散在不同的标签内,不做处理可能无法准备匹配搜索关键字
2、搜索结果出来后通过点击查找上一个或者下一个高亮处,不做处理会重复创建font标签
3、需要给自建的font标签加上自定义属性用于找到当前高亮关键字并滚动到视图开始位置

一、创建dom用于展示后端返回的html形式文档

<div class="html-content" [innerHtml]="fileInfo.fileContent | html"><div>

二、

public setHighLightText(): void {// 文档内容为空if (!this.fileInfo.fileContent) {return;}// 找到页面中渲染文档的dom元素const doms = document.querySelector('.html-content');// 遍历dom找出文本节点const textNodes = this._utilService.getTextNodeList(doms);const textList = this._utilService.getTextInfoList(textNodes);// 拼接文本内容const content = textList.map(({ text }) => text).join('');this.matchList = this._utilService.getMatchList(content, this.searchText);// 重置索引index值this.setRetrievalIndex();this._utilService.replaceMatchResult(textNodes, textList, this.matchList, this.retrievalIndex, 'html-content');}
/*** 遍历DOM树取出所有文本节点* @param dom dom节点* @returns 文本节点集合*/// tslint:disable-next-line: no-anypublic getTextNodeList (dom: any): any[] {const nodeList = [...dom.childNodes];const textNodes = [];while (nodeList.length) {const node = nodeList.shift();if (node.nodeType === node.TEXT_NODE) {textNodes.push(node);} else {nodeList.unshift(...node.childNodes);}}return textNodes;}
  /*** 获取文本节点列表,可以取出所有文本内容并记录每个文本片段在拼接结果中的开始、结束索引* @param textNodes 文本节点集合* @returns 文本集合*/// tslint:disable-next-line: no-anypublic getTextInfoList (textNodes: any[]): ITextData[] {let length = 0;const textList = textNodes.map(node => {const startIdx = length;const endIdx = length + node.wholeText.length;length = endIdx;return {text: node.wholeText,startIdx,endIdx};});return textList;}
  /*** 匹配关键词* @param content 拼接后的文本内容* @param keyword 关键字* @returns 匹配到的关键字列表*/// tslint:disable-next-line: no-anypublic getMatchList (content: string, keyword: string): any[] {const characters = [...'\\[](){}?.+*^$:|'].reduce((r, c) => (r[c] = true, r), {});keyword = keyword.split('').map(s => characters[s] ? `\\${s}` : s).join('[\\s\\n]*');// g: 全局匹 m: 多行匹配 i:不区分大小写const reg = new RegExp(keyword, 'gm');const matchList = [];let match = reg.exec(content);while (match) {matchList.push(match);match = reg.exec(content);}return matchList;}
  /*** 重新设置检索文字index* @param total 匹配到的文字数组长度*/public setRetrievalIndex(): void {const total = this.matchList && this.matchList.length;// this.retrievalIndex为文字检索当前位置if (this.retrievalIndex > total - 1) {this.retrievalIndex = 0;return;} else if (this.retrievalIndex < 0) {this.retrievalIndex = total - 1;}}
  /*** 关键词使用font标签替换* @param textNodes 文本节点* @param textList 文本以及文本气质索引* @param matchList 匹配到的关键字列表*/// tslint:disable-next-line: no-anypublic replaceMatchResult (textNodes: any[], textList: ITextData[], matchList: any[],retrievalIndex: number, eleClassName: string): void {const fontNodes = document.querySelectorAll(`.${eleClassName} font`);if (fontNodes && fontNodes.length) {const validFontNodes = [];// tslint:disable-next-line: prefer-for-offor (let i = 0; i < fontNodes.length; i++) {if(fontNodes[i].innerHTML && fontNodes[i].getAttribute('retrieval') === 'retrieval') {validFontNodes.push(fontNodes[i]);}}if (validFontNodes && validFontNodes.length) {for (let i = 0; i < validFontNodes.length; i++) {this.setFontBgColor(i, retrievalIndex, validFontNodes[i], eleClassName);}return;}}// 对于每一个匹配结果,可能分散在多个标签中,找出这些标签,截取匹配片段并用font标签替换出for (let i = matchList.length - 1; i >= 0; i--) {const match = matchList[i];const matchStart = match.index;const matchEnd = matchStart + match[0].length; // 匹配结果在拼接字符串中的起止索引// 遍历文本信息列表,查找匹配的文本节点for (let textIdx = 0; textIdx < textList.length; textIdx++) {const { text, startIdx, endIdx } = textList[textIdx]; // 文本内容、文本在拼接串中开始、结束索引if (endIdx < matchStart) {continue;} // 匹配的文本节点还在后面if (startIdx >= matchEnd) {break;} // 匹配文本节点已经处理完了let textNode = textNodes[textIdx]; // 这个节点中的部分或全部内容匹配到了关键词,将匹配部分截取出来进行替换const nodeMatchStartIdx = Math.max(0, matchStart - startIdx); // 匹配内容在文本节点内容中的开始索引const nodeMatchLength = Math.min(endIdx, matchEnd) - startIdx - nodeMatchStartIdx; // 文本节点内容匹配关键词的长度if (nodeMatchStartIdx > 0) {textNode = textNode.splitText(nodeMatchStartIdx);} // textNode取后半部分if (nodeMatchLength < textNode.wholeText.length) {textNode.splitText(nodeMatchLength);}const font = document.createElement('font');font.setAttribute('retrieval', 'retrieval');font.innerText = text.substr(nodeMatchStartIdx, nodeMatchLength);font.style.verticalAlign = 'baseline';this.setFontBgColor(i, retrievalIndex, font, eleClassName);textNode.parentNode.replaceChild(font, textNode);}}}
  /*** 设置font背景色*/public setFontBgColor(index: number, retrievalIndex: number, ele: HTMLElement, eleClassName: string): void {if (index === retrievalIndex) {ele.style.background = '#FF838E';const timer = setTimeout(() => {clearTimeout(timer);// 当前高亮滚动到可视区域开始位置ele.scrollIntoView();}, 0);} else {ele.style.background = '#FFDF66';}}

由于需求背景不一样,可能不能完全复用,但思路和核心代码应该可以借鉴的 _ _

angular+TS实现搜索关键字高亮相关推荐

  1. 使用JS实现博客搜索关键字高亮

    说明 最近博客添加了搜索功能,有个需求是要针对搜索结果中搜索关键字需要高亮显示. 以便用户可以更快速的挑选自己中意的文章. 原理就是在渲染列表数据中给含有关键字的文本标签添加自定义class,渲染完毕 ...

  2. 微服务框架 SpringCloud微服务架构 25 黑马旅游案例 25.5 排序和搜索关键字高亮

    微服务框架 [SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务] SpringCloud微服务 ...

  3. 搜索关键字高亮_Django Haystack 全文检索与关键词高亮

    作者:HelloGitHub-追梦人物[1] 文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库[2] 点击本文最下方的"阅读原文"即可获取 博客提供 RS ...

  4. 一分钟让你学会做搜索关键字高亮

    在我们的日常开发中,在搜索框去搜索一个内容,搜索的关键字高亮是一个比较常用的功能.例如下图所示: 我们可以看到,java四个字母是高亮的状态. 那么这个功能是怎么实现的呢? 基本思路: 我们可以用正则 ...

  5. mysql搜索关键字高亮_给搜索关键字添加高亮,加以颜色区分

    问题描述: 如图中所示,当我单击按专业搜索时,筛选出专业中包含有关键字的专业,并且讲输入的关键字用其他颜色区分开来.结果中每个学校和每个专业都是链接. 实现方法: 1.首先找到专业这一列: var f ...

  6. 搜索关键字高亮_SpringBoot+Mybatis-Plus+Elasticsearch 实现关键字搜索高亮展示

    一.概述&介绍 Elasticsearch:Elasticsearch 是基于Lucense 技术的搜索引擎(服务器),将数据进行缓存再进行查询.​ 与数据库查询的比较:​ (1)相当于sql ...

  7. 微信小程序之搜索关键字高亮

    最近项目中有个需求,就是搜索列表中,对应的搜索关键词要高亮,即显示不同的颜色.百度了一番加上自己的理解,实现了该功能 wxml: <view class="search-box&quo ...

  8. vue + element table 实现搜索关键字高亮展示

    本文主要用来记录实现搜索功能后 如何高亮显示关键字,不介绍搜索功能的实现,文末附带的参考连接有更为详细的介绍,有需要的同学可以进行参考 // 搜索框 <div @keyup.enter=&quo ...

  9. js实现搜索关键字高亮

    开发背景:vue项目 方法一: 实现代码: // 关键字变红 function keywordRed (keyword) {if (keyword && keyword !== '') ...

最新文章

  1. python编程下载安卓版-python编程狮app下载|
  2. 根据SAP表名或视图查询后台配置路径
  3. [idea] - 项目启动报错Process finished with exit code 1
  4. centos常用命令_二、Docker镜像是什么?Docker常用命令
  5. 浅谈移动互联网广告设计评论
  6. mysql要将语句反复执行15次_MySQL多表查询疑问
  7. RK3288 制作内核开机logo
  8. 真实用!推荐一款与Swagger媲美的数据库文档生成工具...
  9. (译)响应式图片— srcset 和 sizes 属性
  10. LintCode_13 字符串查找
  11. 新一代多媒体技术与应用的部分课后题
  12. 淘宝网无法确认收货(chrome)
  13. 台式计算机没有声音图标,台式电脑没声音,小扬声器图标也没有。
  14. toms 尺寸 shoes or boots finds
  15. 评选最牛群主v1.0(哈工大Mooc)
  16. 超级记忆/图像数字记忆 110位数字图像转换表 01-10
  17. python 仪表盘图片读数_OpenCV 表盘指针自动读数的示例代码
  18. Maven突然不从私服下载依赖了
  19. html5手电筒样式,利用HTML5实现SVG模拟手电筒照明特效
  20. 解决问题:使用nvm use出现exit status 1与exit status 145乱码

热门文章

  1. swiper自定义图片轮播按钮、分页器
  2. C++代码实现中缀表达式求值(基于中缀表达式转后缀表达式)
  3. 工具及方法 - 在Source Insight中使用代码格式化工具
  4. 什么是ChatGPT
  5. 项目进行时-安全整改-docker中的mysql升级
  6. 牛腩新闻发布系统—如何发布
  7. 安装matlab2014b软件时,在安装进度条完成后,没有弹出产品配置说明
  8. 人物专访 | Artifex Studio合成师兼统筹小姐姐不一样的经历
  9. 同义词 - 搜索引擎
  10. linux crontab 定时关机,Linux系统使用--定时关机的实现以及crontab命令和文件详解...