使用Node,startOffset和endOffset

时间:2017-03-11 13:19:02

标签: javascript html dom range

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

https://jsfiddle.net/k36goyec/

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

var range = window.getSelection().getRangeAt(0);
var node  = range.startContainer

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

var text        = node.parentNode.textContent;
var startOffset = range.startOffset
var endOffset   = range.endOffset

此数据传递给我的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);
},

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

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

    }
},

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

的问题!

range.startOffset/endOffset规范说明如下:

  

如果startNode是Text,Comment或CDATASection类型的节点,   然后startOffset是从一开始的字符数   的StartNode。对于其他Node类型,startOffset是child的数量   startNode开头之间的节点。

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

IndexSizeError: Index or size is negative or greater than the allowed amount

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

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

问:

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

2 个答案:

答案 0 :(得分:2)

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

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

考虑一下这个文件:

<p>Farmer John has a thousand <b>goats</b></p>
<p>and his <b>goats</b> ate all his oats.</p>

一些问题,我的头脑:

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

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

    如果您的选择以其中一个粗体字开头并在结尾处结束,则会出现同样的问题。

  3. 要获得强大的功能,您需要在原点执行范围的序列化,以记录足够的信息,以确保在目标位置进行精确的反序列化。

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

    如果您无法确保两端的DOM结构相同,那么您必须自己动手。您必须识别两端相同的参考点,并确定范围的起始节点/偏移和结束节点/偏移相对于那些参考点

答案 1 :(得分:1)

解决此问题:

  

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

要获取实际的文本节点,可以使用元素的.childnodes属性。如果您有多个,则可以测试nodeType以告知哪些是文本节点。 要找出任何文本节点中的内容,请查看nodeValue属性。