未捕获的IndexSizeError:无法在'Selection'上执行'getRangeAt':0不是有效的索引

时间:2014-04-08 11:16:03

标签: javascript

这里有什么问题?

if ( window.getSelection() ) 
  EditField = window.getSelection().getRangeAt(0);

抛出错误:

  

未捕获的IndexSizeError:无法执行' getRangeAt' on' Selection':0不是有效索引。

4 个答案:

答案 0 :(得分:26)

问题似乎是WebKit特有的;我无法在IE或Firefox中重现它。正如OP已经提到的,Google Chrome上的错误是:

  

未捕获的IndexSizeError:无法执行' getRangeAt' on' Selection':0不是有效索引

Safari有同样的问题,但信息不同:

  

INDEX_SIZE_ERR:DOM例外1:索引或大小为负数,或大于允许值。

通常在简单的WYSIWYG编辑器中发生。例如:



<form name="frm">
    <div contenteditable="true" style="border:1px solid grey;height:8em;width:100%;">
    Text inside my editor.
    </div>
    Click this button to insert some text into the text editor:
    <button type="button" onclick="doInsert('TEST');">Insert</button>
    </form>
    <script>
    function doInsert(text) {
        var sel = window.getSelection && window.getSelection();
        if (sel) {
            var range = sel.getRangeAt(0);              // error here
            var node = document.createTextNode(text);
            range.deleteContents();
            range.insertNode(node);
        }
    }
    </script>
&#13;
&#13;
&#13;

页面加载完毕后,点击按钮;您将在JavaScript控制台(Chrome)或错误控制台(Safari)中看到错误消息。但是,如果在单击按钮之前单击编辑器部分内的任何位置,则错误将

这个问题很容易预防;在致电rangeCount之前始终先检查getRangeAt

function doInsert(text) {
    var sel = window.getSelection && window.getSelection();
    if (sel && sel.rangeCount > 0) {
        var range = sel.getRangeAt(0);
        ...

当然,您可以通过在页面加载时给予编辑器焦点(使用方法focus)来避免这种情况。

但是,有一些罕见的事件会导致编辑器稍后失去其选择范围。到目前为止,我只能通过多选列表控件重现这一点:

&#13;
&#13;
<form name="frm">
  <div contenteditable="true" style="border:1px solid grey;height:8em;width:100%;">
    Click to position the caret anywhere inside this editor section.
  </div>
  Next, select an item from this list:
  <select id="insertables" multiple="multiple">
    <option>foo</option>
    <option>bar</option>
    <option>baz</option>
  </select>
  <br />Finally, click this button to insert the list item into the text editor:
  <button type="button" onclick="doInsert(frm.insertables.value);">Insert</button>
</form>
<script>
  function doInsert(text) {
    var sel = window.getSelection && window.getSelection();
    if (sel) {
      var range = sel.getRangeAt(0); // error here
      var node = document.createTextNode(text);
      range.deleteContents();
      range.insertNode(node);
    }
  }
</script>
&#13;
&#13;
&#13;

同样,我可以通过检查rangeCount来防止错误。但问题仍然是我的按钮没有插入最后一个已知插入位置的所选列表项,就像它应该这样做。方法focus没有帮助;它会将插入符号位置重置为编辑器中的左上角位置。

解决方案是持续保存当前选择范围(为此,陷阱事件SelectionChange):

var savedRange = null;

document.addEventListener("selectionchange", HandleSelectionChange, false);

function HandleSelectionChange() {
    var sel = window.getSelection && window.getSelection();
    if (sel && sel.rangeCount > 0) {
        savedRange = sel.getRangeAt(0);
    }
}

单击按钮时恢复它:

function doInsert(text) {
    var sel = window.getSelection && window.getSelection();
    if (sel && sel.rangeCount == 0 && savedRange != null) {
        sel.addRange(savedRange);
    }
    if (sel && sel.rangeCount > 0) {
        var range = sel.getRangeAt(0);
        var node = document.createTextNode(text);
        range.deleteContents();
        range.insertNode(node);
    }
}

小提琴:http://jsfiddle.net/stXDu/

答案 1 :(得分:2)

我的项目中有一些解决方案

将iframe用作WYSIWYG编辑器

我们将 editwin 设置为iframe的窗口

每次在通过代码向编辑器插入内容之前,您应首先使用以下代码。

editwin.focus();
editwin.document.body.focus();

使用textarea作为编辑

textobj 设为textarea的dom

同样的方式,但不同的代码

textobj.focus();

答案 2 :(得分:1)

解决此问题的完全方法(如JavaScript中90%的所有内容)都是对象检测;选择相关当然不是直接的:

if (window.getSelection().rangeCount >= 1) {var r = window.getSelection().getRangeAt(0);}

当没有选定的文本时,测试将window.getSelection().rangeCount抛出到控制台并且它将返回0;选择它会返回1.我不确定是否以及如何设法让它返回2或更高。

答案 3 :(得分:0)

以下是需要考虑的事项:您的代码中某处已禁用选择吗?如果是这样,在某些情况下,您可能需要首先启用选择,最好是在mousedown事件中,或者在关注元素之前(NB!),然后才能获得范围。这样做解决了我的问题版本。

$('#MyEditableDiv').on('mousedown', function (e) {

    $(document).enableSelection();


});