您的位置:首页 > Web前端 > HTML

浏览器中搜索与高亮文本

2017-01-09 17:09 471 查看
在前段时间开发中, 遇到了搜索和高亮文本的需求. 希望开发一个通用的基于html的搜索与高亮模块,

不但能够应用在编辑器中, 而且也能在普通的HTML页面中使用.

普通HTML页面思路

于是看了看市面上的一些搜索与高亮插件, 如

mark.js 和 一些文章, 如纯客户端页面关键字搜索高亮jQuery插件 张鑫旭-鑫空间-鑫生活, 发现思路基本如下:

收集搜索目标容器的innerHTML

对innerHtml字符串进行处理, 如关键字正则匹配

将处理后的html更新至目标容器的innerHTML

mark.js 做得得更精细些, 但也会修改搜索区域的DOM结构 – 这是我不希望看到的.

个人希望搜索与高亮模块能够满足:

像浏览器自带的搜索功能(
window.find
) 那样, 高亮搜索关键字且不修改搜索区域的DOM结构

能够指定搜索区域的容器, 而不是整个页面(
window.find
搜索整个页面, 无法指定搜索范围)

编辑器思路

富文本编辑器中开发搜索与高亮文本时, 一般使用 Selection/Range 对象来高亮文本.

CKEditor, UEditor 都是这么做的.



如上图,
apollo
是搜索关键字, 高亮的
Apollo
是使用 Selection/Range 来完成的.

这样做的好处是:

不修改搜索区域的DOM结构

缺陷是:

只能同时显示一个结果, 多个结果时, 只能切换显示.

Safari 浏览器的搜索与高亮

Safari 浏览器的搜索功能挺有意思(如下图).



仔细观察, 且猜测其如何实现会发现:

搜索与高亮的整个页面添加了一个蒙板, 覆盖在页面上方

蒙板遇到关键字区域, 开洞露出关键字, 从而产生高亮效果

可以猜想: 这种实现应该也没有修改搜索区域的DOM结构.

新思路

以上搜索与高亮的实现思路各不相同, 能否综利用以满足如下要求呢?

搜索高亮

不修改搜索区域的DOM结构

经过一番思考和coding, 发现以下思路可行:

深度优先遍历&收集搜索区域(container)下所有的textNode节点的相关信息, 并保存在一个数组中.

将数组中所有textNode节点的value 拼凑一个大字符串

搜索关键字时, 在大字符串中搜索, 并记录关键字在大字符串中的出现位置信息(start, end)

将关键字在大字符串的出现位置信息(start, end) 映射成关键字在数组中的textNode节点上的开头结尾信息(start, end)

根据关键字在数组中的textNode节点上的开头结尾信息(start, end), 创建刚好包含关键字的 range (参考 https://developer.mozilla.org/en-US/docs/Web/API/range)

使用 range 的
getClientRects()
获取关键字在窗口中的位置信息(top, left, width, height)数组, 并变换成关键字在页面中的位置信息(top, left, width, height)数组.

根据位置信息(top, left, width, height)数组, 在页面中添加半透明高亮层, 使用绝对定位绘制, 使之悬浮在关键字上方.

以下是搜索
underscor
,
总书记
时的效果图:



如果再优化一下界面, 感觉能实现类似 Safari 浏览器的搜索与高亮效果.

与浏览器原生的搜索与高亮(
window.find
) 相比, 这种思路的缺陷是:

无法高亮
<input/>
,
<textarea/>
中的文本

参考

mark.js

Search Keyword Highlighting JavaScript | The Art of Web

纯客户端页面关键字搜索高亮jQuery插件 张鑫旭-鑫空间-鑫生活

Range - Web APIs | MDN
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息