使用Node,startOffset和endOffset重建Range

Jet*_*rst 7 html javascript dom range

我正在尝试Range()使用websockets在客户端浏览器上重建对象.

https://jsfiddle.net/k36goyec/

首先,我在浏览器中获取Range对象,以及范围开始的Node:

var range = window.getSelection().getRangeAt(0);
var node  = range.startContainer
Run Code Online (Sandbox Code Playgroud)

我通过websockets将三个参数传递给客户端浏览器上的范围构建器函数.

var text        = node.parentNode.textContent;
var startOffset = range.startOffset
var endOffset   = range.endOffset
Run Code Online (Sandbox Code Playgroud)

这个数据传递给我的buildRange函数:

/**
 *
 */
buildRange: function(text, startOffset, endOffset){
    var node = this.getNodeByText(text); // get the Node by its contents

    var range = document.createRange();
    range.setStart(node, startOffset);
    range.setEnd(node, endOffset);

    span = document.createElement('span');
    span.style.backgroundColor = this.color;
    $(span).addClass('hl');
    range.surroundContents(span);
},
Run Code Online (Sandbox Code Playgroud)

正如您在下面看到的,我通过遍历页面上的所有元素并将其内容与文本进行比较来获取客户端浏览器上的节点:

/**
 *
 */
getNodeByText: function(text){
    var all = document.getElementsByTagName("*");
    for (var i = 0; i < all.length; i++) {
        if (all[i].textContent === text) {
            return all[i];
        }

    }
},
Run Code Online (Sandbox Code Playgroud)

我正在使用setStart()和setEnd()来设置节点上我选择的范围.

问题!

range.startOffset/endOffset规范说以下内容:

如果startNode是Text,Comment或CDATASection类型的节点,则startOffset是startNode开头的字符数.对于其他节点类型,startOffset是startNode开头之间的子节点数.

当我选择一系列文本时,我收到以下错误:

IndexSizeError: Index or size is negative or greater than the allowed amount
Run Code Online (Sandbox Code Playgroud)

这是因为我传递的偏移量为0,10(选择了10个字符),但节点是元素节点而不是文本节点.

我似乎无法可靠地获取文本节点,我只能获得元素节点本身...

问:

如何使用节点和偏移可靠地重建范围?

Lou*_*uis 2

其他人已经指出,您面临的直接问题是,当您保存范围数据时,您会在文本节点中获得偏移量,但是当您尝试重新创建范围时,您会使用偏移量作为元素的索引,并且它崩溃。如果你解决了这个问题,你就解决了眼前的问题。

然而,您的整体方法很脆弱。

考虑这样的文档:

<p>Farmer John has a thousand <b>goats</b></p>
<p>and his <b>goats</b> ate all his oats.</p>
Run Code Online (Sandbox Code Playgroud)

我脑子里浮现出一些问题:

  1. 如果您选择第二个“山羊”,您的算法将在第一个“山羊”上重新创建范围,因为它只查找与原始范围具有相同文本的元素。

  2. 如果您选择第二行中以“and”开头并以“ate”结尾的范围,则从原始范围获得的偏移量将在两个不同的文本节点中建立索引:一个包含该文本的文本节点and his 和另一个包含该文本的文本节点包含文本的节点 ate all his oats.您的算法假设只有一个注释要在目的地恢复。可能有不止一个。

    如果您的选择以粗体字之一开始并在外部结束,也会出现同样的问题。

为了拥有强大的功能,您需要在源端执行范围序列化,记录足够的信息以确保在目标端进行精确的反序列化。

有很多方法可以做到这一点。一种方法是确保源端和目标端存在相同的 DOM 结构,并使用Rangy 库的序列化模块来执行序列化和反序列化。如果你能确保两端有相同的 DOM 结构,这就是我会使用的。

如果您无法确保两端具有相同的 DOM 结构,那么您必须自行设计。您必须识别两端相同的参考点,并识别相对于这些参考点的范围的起始节点/偏移量和结束节点/偏移量。