Javascript 获取包含未命名元素的文本选择的开始和结束位置

Javascript 获取包含未命名元素的文本选择的开始和结束位置,javascript,Javascript,我正在尝试制作一个注释工具-用户可以将文本中的某些元素包围在div中。我需要保留原始文本的选择范围和位置 此div包含要注释的文本: 福吧巴兹酒店 使用document.getSelection和getRange可以使用有效的surroundContents。但问题是,在包围第一个标签之后,我无法获得第二个选择的真实文本位置 在被包围的元素之后: 福吧巴兹酒店 如果我选择baz,则anchorStart为0而不是8。这是因为anchorNode现在是TextNode,因为现在有一个从surrou

我正在尝试制作一个注释工具-用户可以将文本中的某些元素包围在div中。我需要保留原始文本的选择范围和位置

此div包含要注释的文本:

福吧巴兹酒店 使用document.getSelection和getRange可以使用有效的surroundContents。但问题是,在包围第一个标签之后,我无法获得第二个选择的真实文本位置

在被包围的元素之后:

福吧巴兹酒店 如果我选择baz,则anchorStart为0而不是8。这是因为anchorNode现在是TextNode,因为现在有一个从surroundContents方法注入的跨度

我没有找到任何解决方案,仅使用div原始内容获得选择位置

注意:我尝试了Rangy库来检查它是否提供了解决方案,但没有。。。 我还检查了doccano接口是如何完成这项工作的,但是代码解密有点复杂,所以方法不容易理解

这是一个例子:

函数注释{ 让selection=document.getSelection; 让range=selection.getRangeAt0; let pre=document.querySelectorpre; pre.innerHTML=`start:${range.startOffset}`; let annotation=document.createElementspan; annotation.classList.addbox; range.surroundContentsannotation; 选择。空; } .盒子{ 背景颜色:黄色 } 注释者{ 填充:1em; 边框:1px纯黑; } 首先尝试选择条形图并添加注释。然后选择baz并注释。您将看到startOffset将为1。

福吧巴兹酒店 注释
假设高亮显示的文本不包含任何已高亮显示的区域,否则surroundContents将无法正常工作:

使用const startContainer=range.startContainer获取包含整个范围的文本节点。这应该与range.endContainer相同 在注释器div内找到它的索引:const index=[…annotator.childNodes].indexOfstartContainer 实际开始偏移量为range.startOffset+先前节点annotator.childNodes[0]、annotator.childNodes[1]、…、annotator.childNodes[index-1]的长度之和 要计算节点的文本长度,请对文本节点使用node.nodeValue.length,或对节点使用node.innerText.length。 或者:

将每个节点相对于原始div的起始偏移量存储在节点的属性/属性中。 对于每个添加的节点,计算内部文本跨距和紧随其后的文本节点的新偏移量。 使用该偏移调整每个节点中的局部偏移。
这样你就不必遍历所有的子对象来获得偏移量;但是,在大多数实际情况下,子节点的数量可以忽略不计。

只需迭代该文本节点之前div的所有子节点,并将其长度之和添加到该文本节点,否?它可能有子节点。例如,doccano不是这样做的。现在我大致按照你们说的做,regexp并添加匹配标记的长度。这不是我的意思。看到答案了吗?我现在就是这么做的,但效率不高,而且可能已经有文字了。即使这是一个有效的答案,但目前在我的项目中,它是这样工作的,似乎其他项目没有这样做。Doccano就是一个很好的例子,但是方法很难理解。但感谢您确认我的第一种方法或多或少类似于您的想法@Metal3d没有效率?我觉得这很有效率。即使已经有1000个选定的区域,计算机也可以非常快速地遍历它们。或者您有其他特殊要求吗?@Metal3d您确定您正确理解了答案吗?无论是否有环绕的文本,这都会起作用;而且我的方法根本不涉及正则表达式。是的,谢谢。。。我理解并重申,我在他人界面上看到的不是相同的方法。我使用regexp使代码更简单,。当我找到元素时,我已经对标记大小进行了迭代求和,等等。。。还有一次,这里是解析元素,而其他接口似乎使用块获得了更好的方法。更好的是,嵌套范围似乎没有什么特殊的意义。我的解释是精确的,您的解释和我的解释之间的唯一区别是,当我使用父outerHTML获取span regexp时,您使用Range父元素作为开头。方法保持不变:我们计算元素大小并与上一个元素求和,以获得下一个位置。