Gau*_*don 7 html javascript google-chrome caret contenteditable
摘要:
我试图实现这样的效果:当用户键入a (
或[
在内容可编辑时div
,第二个)
或]
自动插入,并且插入符号位于它们之间,即(
和之间)
.
键入--
s 的右侧,并查看它在第一行中的工作方式,而在第二行中不起作用.
我的努力:
我正在使用此代码(由Tim Down)来突出显示文本的某些部分并设置光标位置.前者有效但后者没有:(
function getTextNodesIn(node) { // helper
var textNodes = [];
if (node.nodeType == 3) {
textNodes.push(node);
} else {
var children = node.childNodes;
for (var i = 0, len = children.length; i < len; ++i) {
textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
}
}
return textNodes;
}
function highlightText(el, start, end) { // main
if (el.tagName === "DIV") { // content-editable div
var range = document.createRange();
range.selectNodeContents(el);
var textNodes = getTextNodesIn(el);
var foundStart = false;
var charCount = 0,
endCharCount;
for (var i = 0, textNode; textNode = textNodes[i++];) {
endCharCount = charCount + textNode.length;
if (!foundStart && start >= charCount && (start < endCharCount || (start == endCharCount && i < textNodes.length))) {
range.setStart(textNode, start - charCount);
foundStart = true;
}
if (foundStart && end <= endCharCount) {
range.setEnd(textNode, end - charCount);
break;
}
charCount = endCharCount;
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else { // textarea
el.selectionStart = start;
el.selectionEnd = end;
}
}
Run Code Online (Sandbox Code Playgroud)
笔记:
<div>
将有子元素(主要是<br>
s).我的问题:
我花了几个小时搜索这个并没有发现任何有用的东西.有些是关于设置孩子的开始或结束,div
但对我来说,它可以是任何位置,任何地方.
更新:
感谢大家终于完成了开发!
Tim*_*own 11
这是一个更简单的方法.有几点需要注意:
keypress
是唯一可以可靠地检测键入了哪个字符的关键事件.keyup
并且keydown
不会这样做.keypress
事件的默认操作来手动处理括号/括号的插入.演示:
码:
var editableEl = document.getElementById("editable");
editableEl.addEventListener("keypress", function(e) {
var charTyped = String.fromCharCode(e.which);
if (charTyped == "{" || charTyped == "(") {
// Handle this case ourselves
e.preventDefault();
var sel = window.getSelection();
if (sel.rangeCount > 0) {
// First, delete the existing selection
var range = sel.getRangeAt(0);
range.deleteContents();
// Insert a text node at the caret containing the braces/parens
var text = (charTyped == "{") ? "{}" : "()";
var textNode = document.createTextNode(text);
range.insertNode(textNode);
// Move the selection to the middle of the inserted text node
range.setStart(textNode, 1);
range.setEnd(textNode, 1);
sel.removeAllRanges();
sel.addRange(range);
}
}
}, false);
Run Code Online (Sandbox Code Playgroud)
为了实现摘要中所述的目标,请尝试更改当前光标位置的节点值。由于您的代码附加到一个keyup
事件,因此您可以确保范围已经折叠并位于文本节点上(所有这些都发生在按下按键时,这已经被触发)。
function insertChar(char) {
var range = window.getSelection().getRangeAt(0);
if (range.startContainer.nodeType === Node.TEXT_NODE) {
range.startContainer.insertData(range.startOffset, char);
}
}
function handleKeyUp(e) {
e = e || window.event;
var char, keyCode;
keyCode = e.keyCode;
char =
(e.shiftKey ? {
"222": '"',
"57": ')',
"219": '}'
} : {
"219": "]"
})[keyCode] || null;
if (char) {
insertChar(char);
}
}
document.getElementById("editable").onkeyup = handleKeyUp;
Run Code Online (Sandbox Code Playgroud)
另外,我发现您正在用来innerHTML
设置新值(在 中Element.prototype.setText
)。这让我听起来很震惊! innerHTML
完全核爆容器中之前的所有内容。由于光标绑定到特定元素,而这些元素刚刚被破坏,浏览器应该做什么?如果您非常关心光标随后的位置,请尽量避免使用此功能。
至于highlightText
问题,很难说为什么会坏。你的小提琴没有显示它在任何地方使用,我需要查看它的用法来进一步诊断它。但是,我对可能出现的问题有一个想法:
我认为你应该仔细看看getCaretPosition
。您将其视为返回光标位置,但事实并非如此。请记住,对于浏览器来说,您的光标位置始终是一个范围。它总是有开始和结束。有时,当范围折叠时,起点和终点是同一点。然而,您可以获取光标位置并将其视为单个点的想法是一种危险的过度简化。
getCaretPosition
还有另一个问题。对于您的可编辑div
,它执行以下操作:
toString()
并返回结果字符串的长度。正如您所注意到的,某些元素(例如<br />
)会影响 的结果toString()
。有些元素(例如<span></span>
)则不然。为了正确计算,您需要针对某些元素类型微调它,而不是其他元素类型。这将会变得混乱且复杂。如果你想要一个可以输入的数字highlightText
并让它按预期工作,那么你的电流getCaretPosition
不太可能有帮助。
相反,我认为您应该尝试直接将光标的起点和终点作为两个单独的位置进行工作,并进行highlightText
相应的更新。放弃当前的getCaretPosition
并直接使用浏览器的原生概念range.startContainer
、range.startOffset
、range.endContainer
和range.endOffset
。
归档时间: |
|
查看次数: |
5123 次 |
最近记录: |