Uncaught IndexSizeError: Failed to execute 'getRangeAt' on 'Selection': 0 is not a valid index
这是什么问题?
1 2 | if ( window.getSelection() ) EditField = window.getSelection().getRangeAt(0); |
引发错误:
Uncaught IndexSizeError: Failed to execute 'getRangeAt' on 'Selection': 0 is not a valid index.
这个问题似乎是WebKit特有的。我无法在IE或Firefox中复制它。如前所述,OP在Google Chrome上的错误是:
Uncaught IndexSizeError: Failed to execute 'getRangeAt' on 'Selection': 0 is not a valid index
Safari存在相同的问题,但消息有所不同:
INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.
通常发生在简单的所见即所得编辑器中。例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <form name="frm"> Text inside my editor. Click this button to insert some text into the text editor: <button type="button" onclick="doInsert('TEST');">Insert</button> </form> 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); } } |
页面加载后,单击按钮;您将在JavaScript控制台(Chrome)或错误控制台(Safari)中看到错误消息。但是,如果在单击按钮之前单击编辑器部分内的任何位置,则不会发生该错误。
这个问题很容易预防。始终在调用
1 2 3 4 5 | function doInsert(text) { var sel = window.getSelection && window.getSelection(); if (sel && sel.rangeCount > 0) { var range = sel.getRangeAt(0); ... |
当然,可以通过在页面加载时赋予编辑器焦点(使用方法
但是,有些罕见的事件会导致您的编辑器稍后失去选择范围。到目前为止,我只能使用多选列表控件来重现此内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <form name="frm"> Click to position the caret anywhere inside this editor section. 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> 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); } } |
同样,我可以通过检查
一种解决方案是连续保存当前选择范围(为此,陷阱事件
1 2 3 4 5 6 7 8 9 10 | 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); } } |
并在单击按钮时将其还原:
1 2 3 4 5 6 7 8 9 10 11 12 | 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/
解决此问题的确切方法(例如JavaScript中90%的所有内容)是对象检测。选择相关当然不是那么简单:
1 | if (window.getSelection().rangeCount >= 1) {var r = window.getSelection().getRangeAt(0);} |
要在没有选定文本的情况下将
我的项目中有一些解决方案
使用iframe作为WYSIWYG编辑器
我们将editwin设置为iframe的窗口
每次在通过代码向编辑器中插入内容之前,都应首先使用以下代码。
1 2 | editwin.focus(); editwin.document.body.focus(); |
使用textarea作为编辑器
将textobj设置为textarea的dom
一样的方式,但是代码不同
1 | textobj.focus(); |
这里有一些需要考虑的问题:您是否在代码的某处禁用了选择功能?如果是这样,则在某些情况下,您可能希望首先启用选择,最好在发生鼠标按下事件时或在专注于元素之前(NB!),然后再获取范围。这样做已经解决了我的问题版本。
1 2 3 4 5 6 | $('#MyEditableDiv').on('mousedown', function (e) { $(document).enableSelection(); }); |