我正在尝试存储一个contentEditable元素的选择并稍后恢复。
我想观察paste
事件并按原样保存HTML,清除html然后手动插入粘贴的文本,并在所选位置进行一些更改。
看一下这个例子:jsfiddle.net/gEhjZ
当您选择文本的一部分时,点击store
,再次删除选择并点击restore
,它会按预期运行。
但是,当您第一次点击store
时,请点按overwrite html
,然后点击restore
然后尝试.cloneRange()
,将HTML替换为完全相同的HTML。
我认为使用$.extend(true, {}, oldRange)
会有所作为,但事实并非如此。即使是对象的深层副本(sel
)也无法解决问题。只要我覆盖HTML,选择对象TypeError: Value does not implement interface Node.
也会被更改。我觉得更改选择上下文会擦除范围,但我正在尝试将其恢复为完全相同的HTML。
我知道我可以使用rangy,但我真的不想仅仅为这个小功能使用一个巨大的库。我错过了什么?任何帮助将不胜感激!
注意:仅支持Firefox / Chrome,因此不需要使用crossbrowser-hack。
@Tim Down的答案在使用div时有效,但我实际上是在使用iframe。当我做出这个例子时,我认为它没有任何区别。
现在,当我尝试恢复iframe的正文时,我收到以下错误:preSelectionRange.selectNodeContents(containerEl);
位于以下行editable.get(0)
中。我没有从谷歌搜索获得太多。我试图包装正文的内容并恢复包装的html,但我得到了同样的错误。
jsfiddle在这种情况下不起作用,因为它使用iframe来显示结果本身,所以我在这里举了一个例子:snipt.org/AJad3
同样没有包裹:snipt.org/AJaf0
更新2:
当然,我认为我必须使用start
。但现在iframe选择的end
和{{1}}为0.请参阅snipt.org/AJah2
答案 0 :(得分:14)
您可以使用以下功能保存和恢复角色位置:
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();
};
}
答案 1 :(得分:1)
提供的解决方案效果很好。
替换那条线
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
由
if (!foundStart && savedSel.start >= charIndex && savedSel.start < nextCharIndex) {
防止 Chrome/Edge 选择上一行的结尾