错误时尝试使用setStart和setEnd on Range:Uncaught IndexSizeError:无法在'Range'上执行'setEnd'

时间:2015-04-23 18:08:14

标签: javascript range

当我尝试使用范围时,我在控制台上收到此错误:

Uncaught IndexSizeError: Failed to execute 'setEnd' on 'Range': The offset 2 is larger than or equal to the node's length (0).

这是我的剧本:

<script type="text/javascript">
    function gotMark() {
        var range = document.createRange();
        var startNode = document.getElementById("dividTeste1").firstChild;

        range.setStart(startNode, 0);
        range.setEnd(startNode, 2);

        var newNode = document.createElement("span");
        range.surroundContents(newNode);
    }
</script>

并且页面:

<div class="ui-block-a" id="divid" value="div1">
    <div style="background-color: black; color: white; padding: 20px;" id="divid2">
        <h2>London</h2>
        <p id="dividTeste1">London is the capital city of England. It is the most
            populous city in the United Kingdom, with a metropolitan area of
            over 13 million inhabitants.</p>
    </div>

    <div style="background-color: black; color: white; padding: 20px;" id="divid2">
        <h2>London</h2>
        <p id="dividTeste2">London is the capital city of England. It is the most
            populous city in the United Kingdom, with a metropolitan area of
            over 13 million inhabitants.</p>
    </div>
</div>
<input type="button" value="Marcar com range" onClick="gotMark()"
        id="marcarconranger12" />

我尝试按照dom range.setStart / setEnd中的说明选择开始和结束位置。

3 个答案:

答案 0 :(得分:0)

我的解决方案我的错误有一行

function gotMark() {
    var range = document.createRange();
    var startNode = document.getElementById("dividTeste1").firstChild;

    range.setStart(startNode, 0);
    range.setEnd(startNode, 2);

    var newNode = document.createElement("span");
   *newNode.className = 'highlight-yellow';*

    range.surroundContents(newNode);
}

现在已经选择了

答案 1 :(得分:0)

虽然 OP 的代码似乎是安全且有界限的,但在同一节点上进行多次操作时经常会出现问题,这会改变其特性并丢弃您可能已经进行的后续偏移计算。

例如,假设我们要为开始-结束对数组上的段落添加突出显示。最简单的方法是向前迭代这些对并为每个开始-结束范围执行插入:

const highlightPositions = (textEl, positions) =>
  positions.forEach(([start, end]) => {
    const range = document.createRange();
    range.setStart(textEl.firstChild, start);
    range.setEnd(textEl.firstChild, end);
    const span = document.createElement("span");
    span.style.background = "#0f6";
    range.surroundContents(span);
  })
;

const positions = [[0, 3], [8, 11]];
highlightPositions(document.querySelector("p"), positions);
<p>foo bar baz</p>

这里的解决方法是确保位置已排序且不重叠,然后向后迭代,以便当节点的内容更改时,内容中较早的索引偏移量不会受到影响。

const highlightPositions = (textEl, positions) =>
  positions.slice().reverse().forEach(([start, end]) => {
    const range = document.createRange();
    range.setStart(textEl.firstChild, start);
    range.setEnd(textEl.firstChild, end);
    const span = document.createElement("span");
    span.style.background = "#0f6";
    range.surroundContents(span);
  })
;

const positions = [[0, 3], [8, 11]];
highlightPositions(document.querySelector("p"), positions);
<p>foo bar baz</p>

计算跨越多个节点的偏移量时也会出现这个问题;确保偏移量对于作为范围的第一个参数给出的节点是本地的。

还有许多其他策略可以避免这个问题,包括 Node.normalize() 将文本子项重新粘合在一起,在新节点或字符串上构建所需的文本并在准备好时设置 .innerHTML 等。

答案 2 :(得分:0)

const highlightPositions = (textEl, positions) =>
  positions.slice().reverse().forEach(([start, end]) => {
    const range = document.createRange();
    range.setStart(textEl.firstChild, start);
    range.setEnd(textEl.firstChild, end);
    const span = document.createElement("span");
    span.style.background = "#0f6";
    range.surroundContents(span);
  })
;

const positions = [[0, 3], [8, 11]];
highlightPositions(document.querySelector("p"), positions);
<p>foo bar baz</p>