一直都想做一个 js 库, 而且 github 上没有太多重复的轮子那种 (轮子太多自己造就没必要了), 最好是自己会用得上. 思前想后, 决定做一个高亮文字的 js 库. 刚好最近接触一段时间 typescript, 可以拿来练练手, 毕竟自己的东西怎么折腾都可以.
如何让一个元素的文字高亮, 或者鼠标选中的文字高亮?
让一个元素的文字高亮很简单, 直接
<p > 这是一段文字 </p> ==> <p><mark > 这是一段文字 </mark></p>
可以为元素内的文字加上一个容器, 并且不能够影响到文字的换行. 之后为 mark 元素加上样式就可以了
让鼠标选中的文字高亮
高亮鼠标选中的文字需要处理的情况就复杂一点了
例如
jsfiddle 例子 https://jsfiddle.net/LUPIN34/8Lszpkox/6/
当鼠标选中一个元素中的部分文字
- // 鼠标选中了在 p 元素中的一部分文字, 假设是 "一段" 这两个字
- // 那么则需要处理成以下模样
- <p > 这是一段文字 </p> ==> <p > 这是 < mark > 一段 </mark > 文字 </p>
鼠标选中的文字跨越多个元素
- <div>
- <p>1 这是一段文字 </p>
- </div>
- <div>
- <p>2 这是一段文字 </p>
- </div>
处理以上的这些情况, 则需要用到 https://developer.mozilla.org/zh-CN/docs/web/API/Range 对象
- document.addEventListener('click', (event) => {
- let selection = window.getSelection();
- console.log(selection)
- if (selection.rangeCount) {
- let range = selection.getRangeAt(0)
- console.log(range)
- }
- })
我们可以通过 Selection 对象进而拿到 Range. 在 chrome 上我们用鼠标只能选中一个 Range,firefox 上按住 ctrl 则可以多选.
Range.extractContents()
把 Range 的内容从文档树移动到文档片段中. 这会造成选区内的元素消失在 dom 树上
Range.insertNode()
在 Range 的起点处插入节点.
通过 Range.extractContents() 可以拿到 documentFragment, 之后对 document Fragment 进行相应的处理之后插入到 Range 中.
但是简单的进行 insertNode 会发生换行的效果.
具体原因看看代码就知道了. https://jsfiddle.net/LUPIN34/8Lszpkox/18/
例子中的 p 元素插入到 Range 时, 包含了其父元素 div, 所以发生换行.
所以这里面还是有很多坑要踩, 下次有空再写吧.
最后附上自己的写的 js 库 https://github.com/Ge-Ge/highlight , 虽然还有很多待完善的地方. 喜欢就给个 start 吧.
来源: https://juejin.im/entry/5b2bbe336fb9a00e6714993f