如何用JS实现“划词高亮标记”的在线笔记功能

  1. offset: range.startOffset
  1. };
  1. const end = {
  1. node: range.endContainer,
  1. offset: range.endOffset
  1. };

Range 对象包含了选区的开始与结束信息,其中包括节点(node)与文本偏移量(offset)。节点信息不用多说,这里解释一下 offset 是指什么:例如,标签

这是一段文本的示例

,用户选取的部分是“一段文本”这四个字,这时首尾的 node 均为 p 元素内的文本节点(Text Node),而 startOffset 和 endOffset 分别为 2 和 6。

2)首尾文本节点拆分

理解了 offset 的概念后,自然就发现有个问题需要解决。由于用户选区(selection)可能只包含一个文本节点的一部分(即 offset 不为 0),所以我们最后得到的用户选区所包含的节点里,也只希望有首尾文本节点的这“一部分”。对此,我们可以使用 .splitText() 拆分文本节点:

  1. // 首节点
  1. if (curNode === $startNode) {
  1. if (curNode.nodeType === 3) {
  1. curNode.splitText(startOffset);
  1. const node = curNode.nextSibling;
  1. selectedNodes.push(node);
  1. }
  1. }
  1. // 尾节点
  1. if (curNode === $endNode) {
  1. if (curNode.nodeType === 3) {
  1. const node = curNode;
  1. node.splitText(endOffset);
  1. selectedNodes.push(node);
  1. }
  1. }

以上代码会依据 offset 对文本节点进行拆分。对于开始节点,只需要收集它的后半部分;而对于结束节点则是前半部分。

3)遍历 DOM 树

到目前为止,我们准确找到了首尾节点,所以下一步就是找出“中间”所有的文本节点。这就需要遍历 DOM 树。

“中间”加上引号是因为,在视觉上这些节点是位于首尾之间的,但由于 DOM 不是线性结构而是树形结构,所以这个“中间”换成程序语言,就是指深度优先遍历时,位于首尾两节点之间的所有文本节点。DFS 的方法有很多,可以递归,也可以用栈+循环,这里就不赘述了。

需要提一下的是,由于我们是要为文本节点添加高亮背景,因此在遍历时只会收集文本节点。

  1. if (curNode.nodeType === 3) {
  1. selectedNodes.push(curNode);
  1. }

3.2. 如何为文本节点添加背景色?

这一步本身并不困难。在上一步的基础上,我们已经选出了所有被用户选中的 文本节点(包括拆分后的首尾节点)。对此,一个最直接的方法就是为其“包裹上”一个带背景样式的元素。

具体的,我们可以给每个文本节点外加上一个 class 为 highlight 的 元素;而背景样式则通过 CSS .highlight 选择器设置。

  1. // 使用上一步中封装的方法获取选区内的文本节点
  1. const nodes = getSelectedNodes(start, end);
  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值