Javascript 无法在HTML修改后恢复选择,即使它是相同的HTML

Javascript 无法在HTML修改后恢复选择,即使它是相同的HTML,javascript,jquery,range,selection,contenteditable,Javascript,Jquery,Range,Selection,Contenteditable,我正在尝试存储contentEditable元素的选择,并在以后还原它 我想观察粘贴事件并像以前一样存储HTML,清除HTML,然后在所选位置手动插入粘贴的文本并进行一些更改 看看这个例子: 当您选择文本的一部分时,点击store,再次删除所选内容并点击restore,它将按预期工作 但是,当您第一次点击store,然后点击overwrite HTML,用完全相同的HTML替换HTML,然后尝试恢复时,什么也没有发生 我认为使用.cloneRange会有所不同,但不会。即使是对象$.extend

我正在尝试存储contentEditable元素的选择,并在以后还原它

我想观察粘贴事件并像以前一样存储HTML,清除HTML,然后在所选位置手动插入粘贴的文本并进行一些更改

看看这个例子:

当您选择文本的一部分时,点击store,再次删除所选内容并点击restore,它将按预期工作

但是,当您第一次点击store,然后点击overwrite HTML,用完全相同的HTML替换HTML,然后尝试恢复时,什么也没有发生

我认为使用.cloneRange会有所不同,但不会。即使是对象$.extendtrue,{},oldRange的深度副本也不会起作用。一旦我覆盖HTML,选择对象sel也会被更改。对我来说,更改选择上下文将删除范围是有意义的,但我正在尝试将其还原为完全相同的HTML

我知道我可以使用,但我真的不想为了这个小功能而使用一个巨大的库。我错过了什么?任何帮助都将不胜感激

注意:只有Firefox/Chrome,所以不需要交叉浏览器

更新: @Tim Down的答案在使用div时有效,但实际上我使用的是iframe。当我举这个例子时,我认为这不会有任何区别

现在,当我尝试恢复iframe的主体时,我得到以下错误:TypeError:Value未实现接口节点。在下一行的预选范围中。选择NodeContentsContainerEL;。我没有从谷歌搜索中得到多少。我试图包装正文的内容并恢复包装的html,但我得到了相同的错误

在这种情况下,jsfiddle不起作用,因为它使用iframe来显示结果本身,所以我在这里举了一个例子:

同样,不带包装:

更新2:
当然,我想我必须使用editable.get0。但是现在iframe选择的开始和结束是0。请参见

您可以使用以下功能保存和恢复角色位置:

我稍微调整了这些函数,以用于iframe中的元素

演示:

代码:


非常感谢,该范围现在已正确保存,但不知怎的,它无法恢复选择@koko:初始脚本运行时,iframe文档可能没有完全加载。我建议在单击处理程序中使用$'iframe'.contents.find'body'[0]而不是editable.get0。文档已完全加载,我将在粘贴事件中调用此函数。但是,doc变量是未定义的containerrel.ownerDocument。Chrome并不介意,而Firefox介意。稍后我会看一看,我想剩下的问题会相对容易解决。@koko:containerEl.ownerDocument未定义表示containerEl有问题,例如已从文档中删除。不过我想有一个限制。将光标放置在下一空行的开头并保存所选内容,恢复所选内容时,将光标放置在上一行的末尾。有没有办法克服它??
var saveSelection, restoreSelection;

if (window.getSelection && document.createRange) {
    saveSelection = function(containerEl) {
        var doc = containerEl.ownerDocument, win = doc.defaultView;
        var range = win.getSelection().getRangeAt(0);
        var preSelectionRange = range.cloneRange();
        preSelectionRange.selectNodeContents(containerEl);
        preSelectionRange.setEnd(range.startContainer, range.startOffset);
        var start = preSelectionRange.toString().length;

        return {
            start: start,
            end: start + range.toString().length
        };
    };

    restoreSelection = function(containerEl, savedSel) {
        var doc = containerEl.ownerDocument, win = doc.defaultView;
        var charIndex = 0, range = doc.createRange();
        range.setStart(containerEl, 0);
        range.collapse(true);
        var nodeStack = [containerEl], node, foundStart = false, stop = false;

        while (!stop && (node = nodeStack.pop())) {
            if (node.nodeType == 3) {
                var nextCharIndex = charIndex + node.length;
                if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
                    range.setStart(node, savedSel.start - charIndex);
                    foundStart = true;
                }
                if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
                    range.setEnd(node, savedSel.end - charIndex);
                    stop = true;
                }
                charIndex = nextCharIndex;
            } else {
                var i = node.childNodes.length;
                while (i--) {
                    nodeStack.push(node.childNodes[i]);
                }
            }
        }

        var sel = win.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    };
} else if (document.selection) {
    saveSelection = function(containerEl) {
        var doc = containerEl.ownerDocument, win = doc.defaultView || doc.parentWindow;
        var selectedTextRange = doc.selection.createRange();
        var preSelectionTextRange = doc.body.createTextRange();
        preSelectionTextRange.moveToElementText(containerEl);
        preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
        var start = preSelectionTextRange.text.length;

        return {
            start: start,
            end: start + selectedTextRange.text.length
        };
    };

    restoreSelection = function(containerEl, savedSel) {
        var doc = containerEl.ownerDocument, win = doc.defaultView || doc.parentWindow;
        var textRange = doc.body.createTextRange();
        textRange.moveToElementText(containerEl);
        textRange.collapse(true);
        textRange.moveEnd("character", savedSel.end);
        textRange.moveStart("character", savedSel.start);
        textRange.select();
    };
}