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

kok*_*oko 5 javascript jquery range selection contenteditable

我正在尝试存储一个contentEditable元素的选择,并在以后恢复它.

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

看一下这个例子:jsfiddle.net/gEhjZ

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

但是当你第一次点击时store,然后通过点击替换完全相同的HTML overwrite html,然后尝试restore,没有任何反应.

我认为使用.cloneRange()会有所作为,但事实并非如此.即使是object($.extend(true, {}, oldRange))的深层副本也无法解决问题.只要我覆盖HTML,选择对象sel也会被更改.对我来说,更改选择上下文会擦除范围是有道理的,但我正在尝试将其恢复为完全相同的HTML.

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

注意:只有Firefox/Chrome,因此不需要使用crossbrowser-hacks.

更新:

@Tim Down的答案在使用div时有效,但我实际上是在使用iframe.当我做出这个例子时,我认为它没有任何区别.

现在,当我尝试恢复iframe的正文时,我收到以下错误:TypeError: Value does not implement interface Node.在以下行中preSelectionRange.selectNodeContents(containerEl);.我没有从谷歌搜索获得太多.我试图包装正文的内容并恢复包装的html,但我得到了同样的错误.

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

并且没有包装:snipt.org/AJaf0

更新2:editable.get(0)当然, 我认为我必须使用它.但现在startendiframe的选择是0看snipt.org/AJah2

Tim*_*own 14

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

/sf/answers/976526351/

我已经稍微调整了这些功能,以便为iframe中的元素工作.

演示:http://jsfiddle.net/timdown/gEhjZ/4/

码:

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();
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然我猜有一个限制。将光标放在下一个空行的开头并保存选择,在恢复选择时将光标放在上一行的末尾。有办法克服吗?? (2认同)