选中文本高亮并且存储,后续数据回显功能实现(数据会经过后端数据库)

2 阅读3分钟

主要语法

  • const selection = window.getSelection();
    • getSelection()window的内置方法,作用是获取你当前在页面上通过鼠标拖拽、键盘操作选中的内容对应的「Selection 对象」
  • const range = selection.getRangeAt(0);
    • Selection对象(即selection支持多个不连续的选中范围(比如部分浏览器中,按住Ctrl键可以拖拽选中多处不相邻的文本),每个选中范围都是一个Range对象。
    • 获取第一个(也是日常开发中最常用的,默认单区域选中时唯一的)
  • range.startContainer/range.endContainer/range.commonAncestorContainer
    • 选中范围的「起始容器」/选中范围的「结束容器」/选中范围的「最近共同祖先」
    • 返回的节点类型有两种:「元素节点」(如<p><div>,节点类型nodeType=1)和「文本节点」(如标签内的文字内容,节点类型nodeType=3
  • range.surroundContents()
    • 「用一个指定的 DOM 元素,包裹住当前 Range 对象所选中的全部内容」,简单说就是给页面上你选中的内容(文字、节点等)“套一个外层容器标签”(比如给选中的文字套一个 <span> 做高亮、套 <a> 做超链接等)。

完整的开发思路(包括弯路)

  • 我先使用的是document.addEventListener('selectionchange')监听选中文本的变化,document.querySelector().addEventListener('selectionchange')发现报错;随即使用了range.commonAncestorContainer+document.querySelector().contains()实现选中的文本要求在指定位置;从此我以为基础功能实现了毕竟数据存储下来。(剩下的就是回显了)。又发现,其实document.addEventListener一直监听也没啥用,随即使用了document.querySelector().addEventListener('mouseup'
  • 后续发现能选中后再次选中,或者包含选中的文本。这不是我想要的功能。所以就存在了range.startContainer/range.endContainer判断是否在我新加的标签之中。还有选中的文本是否包含新加的标签之中。该功能实现。
  • 从此就开始是错误逻辑:我想回显问题了,想着存储字符串下标和字符串长度,那么回显不就简单了?但是,你每次选中的情况下都会追加span标签,然后使用innerHtml获取字段,但是呢怎么获取字段呢?比如我选择的是'。'这样稀疏平常的字段,但是你咋知道我选择是第几个呢?所以陷入死循环了。
  • 这个我就暂时掠过,后续再说,实在不好弄,我就沟通一下取消这个功能了,毕竟我的实力不允许。。。。
  • 后续解决的就是:要求通过数据,删除追加的span数据,我刚开始想的就是,存储的数据直接存储element,这样删除不久很简单了嘛?还有题外话,range.surroundContents(存储的element)包含数据。但是呢,我需要存入后台数据库,直接存入element数据显然不对,后面我就改成存储uuid了。只需要在element.setAttribute("data-uuid",uuid)就行了。至此,该功能实现。
  • 回头看回显问题,我没必要通过数据去回显啊!我可以直接存储两份数据。就是document.querySelector().innerHmtl和存储的uuid数组数据。反正删除可以实现啊!

具体功能实现

思考,其实主要功能就是这些,但是还需要添加一些具体代码才能应用项目上。由此,我将该功能提取出来。写了一个插件。(ai写的,其实上述的思考代码也是ai写的。getSelection这个东西我都不知道存在).

由此生成了插件,插件地址www.npmjs.com/package/lk-…