【问题标题】:Error when trying to use setStart and setEnd on Range: Uncaught IndexSizeError: Failed to execute 'setEnd' on 'Range'尝试在 Range 上使用 setStart 和 setEnd 时出错:未捕获的 IndexSizeError:无法在“Range”上执行“setEnd”
【发布时间】:2015-04-23 18:08:13
【问题描述】:

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

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 的说明选择开始和结束位置。

【问题讨论】:

    标签: javascript range


    【解决方案1】:

    我通过一行找到了错误的解决方案:

    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'; // <-- added
    
        range.surroundContents(newNode);
    }
    

    现在选择已经跨越。

    【讨论】:

      【解决方案2】:

      虽然 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);
      &lt;p&gt;foo bar baz&lt;/p&gt;

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

      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);
      &lt;p&gt;foo bar baz&lt;/p&gt;

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

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

      【讨论】:

        【解决方案3】:

        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);
        &lt;p&gt;foo bar baz&lt;/p&gt;

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-19
        • 1970-01-01
        • 2022-01-13
        • 1970-01-01
        • 2020-12-18
        相关资源
        最近更新 更多