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

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

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

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

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

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

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

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

注意:只有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) 。 但现在iframe选择的startend是0.参见snipt.org/AJah2

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

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

我已经稍微调整了这些函数来处理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(); }; }