问题是 Rangy 的保存/恢复选择module的工作方式是将不可见的标记元素插入到选择边界所在的 DOM 中,然后您的代码删除所有 HTML 标记,包括 Rangy 的标记元素(如错误消息所示)。您有两个选择:
- 转向 DOM 遍历解决方案来为数字着色,而不是
innerHTML
. 这将更可靠,但更多参与。
- 实现另一种基于字符索引的选择保存和恢复。这通常是脆弱的,但在这种情况下会做你想做的。
更新
我已经为 Rangy 敲了一个基于字符索引的选择保存/恢复(上面的选项 2)。这有点粗糙,但它可以完成这种情况。它通过遍历文本节点来工作。我可能会以某种形式将其添加到 Rangy 中。(2012 年 6 月 5 日更新: 我现在已经以更可靠的方式为 Rangy 实现了这一点。)
jsFiddle:http : //jsfiddle.net/2rTA5/2/
代码:
function saveSelection(containerEl) {
var charIndex = 0, start = 0, end = 0, foundStart = false, stop = {};
var sel = rangy.getSelection(), range;
function traverseTextNodes(node, range) {
if (node.nodeType == 3) {
if (!foundStart && node == range.startContainer) {
start = charIndex + range.startOffset;
foundStart = true;
}
if (foundStart && node == range.endContainer) {
end = charIndex + range.endOffset;
throw stop;
}
charIndex += node.length;
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
traverseTextNodes(node.childNodes[i], range);
}
}
}
if (sel.rangeCount) {
try {
traverseTextNodes(containerEl, sel.getRangeAt(0));
} catch (ex) {
if (ex != stop) {
throw ex;
}
}
}
return {
start: start,
end: end
};
}
function restoreSelection(containerEl, savedSel) {
var charIndex = 0, range = rangy.createRange(), foundStart = false, stop = {};
range.collapseToPoint(containerEl, 0);
function traverseTextNodes(node) {
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);
throw stop;
}
charIndex = nextCharIndex;
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
traverseTextNodes(node.childNodes[i]);
}
}
}
try {
traverseTextNodes(containerEl);
} catch (ex) {
if (ex == stop) {
rangy.getSelection().setSingleRange(range);
} else {
throw ex;
}
}
}
function formatText() {
var el = document.getElementById('pad');
var savedSel = saveSelection(el);
el.innerHTML = el.innerHTML.replace(/(<([^>]+)>)/ig,"");
el.innerHTML = el.innerHTML.replace(/([0-9])/ig,"<font color='red'>$1</font>");
// Restore the original selection
restoreSelection(el, savedSel);
}