【问题标题】:Set Selection Start and End in a Contentedible在 Contentedible 中设置选择开始和结束
【发布时间】:2013-04-05 02:25:17
【问题描述】:

我正在尝试为采用基于语法的格式的网页创建 JavaScript 编辑器。它使用onkeyup 完全替换了<pre> 标签的innerHTML。但是,这会导致插入符号被移动到编辑器的开头。

我能找到的唯一解决方案是在进行更改之前获取选择开始和结束的偏移量,然后在最后设置它们。我获取选择开始和结束的代码是从https://stackoverflow.com/a/4812022/2093695修改的:

var selStart, selEnd;
if (typeof window.getSelection != "undefined") {
    var range = window.getSelection().getRangeAt(0);
    var preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(editor);
    preCaretRange.setEnd(range.endContainer, range.endOffset);
    selStart = preCaretRange.toString().length;
    selEnd = selStart + range.toString().length;
} else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
    var textRange = document.selection.createRange();
    var preCaretTextRange = document.body.createTextRange();
    preCaretTextRange.moveToElementText(editor);
    preCaretTextRange.setEndPoint("EndToEnd", textRange);
    selStart = preCaretTextRange.text.length;
    selEnd = selStart + textRange.text.length;
} else selStart = 0;

至少在 Firefox 中,这部分工作正常。我的问题是 setting 选择。我目前的情况如下:

// restore selection
if (selStart) {
    if (range) {
        range = window.getSelection().getRangeAt(0);
        range.setStart(editor,selStart);
        range.setEnd(editor,selEnd);
        // Doesn't work, in FF at least
        // Behavior: when there are no tags,
        //     for 0, caret set at beginning
        //     for 1, caret set at end
        //     for anything greater, "IndexSizeError: Index or size is negative or greater than the allowed amount"
        // when the editor contains tags,
        //     for 0, caret set at beginning of editor
        //     for 1, caret set at beginning of first tag (unless same as start of editor)
        //     for 2, caret set at end of first tag
        //     for 3, caret set at beginning of second tag
        //     for 4, caret set at end of second tag, and so on
        //     for a number that is 1 greater than whatever number would set the caret at the end of the last tag, caret set at end of editor
        //     for a number greater than that, same error as before
    } else if (document.selection && document.selection.createRange) {
        // Not sure what to do here
    }
}

setStartsetEnd 应该是这样工作的吗?我究竟做错了什么?有没有更好的方法来设置选择的开始和结束,最好不使用库?

【问题讨论】:

  • 请记住直接编辑innerHTML 会导致撤消/重做缓冲区被擦除。在开发tabIndent.js 时遇到了类似的问题。
  • @Julian:感谢您的提醒。我知道这一点,并考虑使用某种替代方法,例如使编辑器的全部内容成为一个范围,并使用 var code = range.toString(); 后跟 range.deleteContents();code = range.createContextualFragment(code);range.insertNode(code);

标签: javascript range selection contenteditable


【解决方案1】:

我为此发布了几个不同的功能。我找不到我最近的一个,但下面有一个指向 jsFiddle 的链接,其中包含一个应该有用的 restoreSelection() 函数:

https://stackoverflow.com/a/7404126/96100

更新:我找到了此代码的更新版本。它应该工作相同,但内部更优雅。

https://stackoverflow.com/a/13950376/96100

【讨论】: