replace innerHTML in contenteditable div(替换 contenteditable div 中的 innerHTML)
问题描述
我需要在 contenteditable div 中实现数字高亮(将来我会添加更复杂的规则).问题是当我使用 javascript 替换插入新内容时,DOM 更改和 contenteditable div 失去焦点.我需要的是专注于当前位置的插入符号的 div,这样用户就可以毫无问题地输入,而我的功能简单地突出显示数字.谷歌搜索我认为 Rangy 库是最好的解决方案.我有以下代码:
i need to implement highlight for numbers( in future im add more complex rules ) in the contenteditable div. The problem is When im insert new content with javascript replace, DOM changes and contenteditable div lost focus. What i need is keep focus on div with caret on the current position, so users can just type without any issues and my function simple highlighting numbers. Googling around i decide that Rangy library is the best solution. I have following code:
function formatText() {
var savedSel = rangy.saveSelection();
el = document.getElementById('pad');
el.innerHTML = el.innerHTML.replace(/(<([^>]+)>)/ig,"");
el.innerHTML = el.innerHTML.replace(/([0-9])/ig,"<font color='red'>$1</font>");
rangy.restoreSelection(savedSel);
}
<div contenteditable="true" id="pad" onkeyup="formatText();"></div>
问题是在函数结束工作重心回到 div 之后,但插入符号始终指向 div begin,我可以在任何地方键入,除了 div begin.Rangy 警告之后的 console.log 类型:模块 SaveRestore:标记元素已被删除.无法恢复选择.
请帮我实现这个功能.我对另一个解决方案持开放态度,而不仅仅是 rangy 库.谢谢!
The problem is after function end work focus is coming back to the div, but caret always point at the div begin and i can type anywhere, execept div begin. Also console.log types following Rangy warning: Module SaveRestore: Marker element has been removed. Cannot restore selection.
Please help me to implement this functional. Im open for another solutiona, not only rangy library. Thanks!
http://jsfiddle.net/2rTA5/ 这是 jsfiddle,但它不能正常工作(没有当我在我的 div 中输入数字时发生),不知道可能是我(第一次通过 jsfiddle 发布代码)或资源不支持 contenteditable.UPD* 我在 stackoverflow 上读到了类似的问题,但解决方案不适合我的情况:(
http://jsfiddle.net/2rTA5/ This is jsfiddle, but it dont work properly(nothing happens when i typed numbers into my div), dunno maybe it me (first time post code via jsfiddle) or resource doesnt support contenteditable. UPD* Im read similar problems on stackoverflow, but solutions doesnt suit to my case :(
推荐答案
问题是 Rangy 的保存/恢复选择模块通过将不可见的标记元素插入到选择边界所在的 DOM 中来工作,然后您的代码会去除所有 HTML 标记,包括 Rangy 的标记元素(如错误消息所示).你有两个选择:
The problem is that Rangy's save/restore selection module works by inserting invisible marker elements into the DOM where the selection boundaries are and then your code strips out all HTML tags, including Rangy's marker elements (as the error message suggests). You have two options:
- 使用 DOM 遍历解决方案来为数字着色而不是
innerHTML
.这将更可靠,但涉及更多. - 实现一个替代的基于字符索引的选择保存和恢复.这通常很脆弱,但在这种情况下会做你想做的事.
- Move to a DOM traversal solution for colouring the numbers rather than
innerHTML
. This will be more reliable but more involved. - Implement an alternative character index-based selection save and restore. This would be generally fragile but will do what you want in this case.
更新
我已经为 Rangy(上面的选项 2)敲了一个基于字符索引的选择保存/恢复.这有点粗糙,但它可以完成这种情况.它通过遍历文本节点来工作.我可能会以某种形式将它添加到 Rangy 中.(2012 年 6 月 5 日更新: 我现在以更可靠的方式为 Rangy 实现了这一点.)
I've knocked up a character index-based selection save/restore for Rangy (option 2 above). It's a little rough, but it does the job for this case. It works by traversing text nodes. I may add this into Rangy in some form. (UPDATE 5 June 2012: I've now implemented this, in a more reliable way, for 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);
}
这篇关于替换 contenteditable div 中的 innerHTML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:替换 contenteditable div 中的 innerHTML
基础教程推荐
- 在 JS 中获取客户端时区(不是 GMT 偏移量) 2022-01-01
- 角度Apollo设置WatchQuery结果为可用变量 2022-01-01
- 悬停时滑动输入并停留几秒钟 2022-01-01
- 在for循环中使用setTimeout 2022-01-01
- 动态更新多个选择框 2022-01-01
- Karma-Jasmine:如何正确监视 Modal? 2022-01-01
- 有没有办法使用OpenLayers更改OpenStreetMap中某些要素 2022-09-06
- 我什么时候应该在导入时使用方括号 2022-01-01
- 当用户滚动离开时如何暂停 youtube 嵌入 2022-01-01
- 响应更改 div 大小保持纵横比 2022-01-01