Javascript 尝试修改文档的文本onkeydown会错误地插入文本
我有以下html:Javascript 尝试修改文档的文本onkeydown会错误地插入文本,javascript,html,Javascript,Html,我有以下html: <html> <head> <script> function myKeyDown() { var myDiv = document.getElementById('myDiv'); myDiv.innerHTML = myDiv.innerHTML.replace(/(@[a-z0-9_]+)/gi, '<strong>$1</strong>'); } function init() {
<html>
<head>
<script>
function myKeyDown()
{
var myDiv = document.getElementById('myDiv');
myDiv.innerHTML = myDiv.innerHTML.replace(/(@[a-z0-9_]+)/gi, '<strong>$1</strong>');
}
function init()
{
document.addEventListener('keydown', myKeyDown, false);
document.designMode = "on";
}
window.onload = init;
</script>
</head>
<body>
<div id="myDiv">
This is my variable name: @varname. If I type here things go wrong...
</div>
</body>
</html>
函数myKeyDown()
{
var myDiv=document.getElementById('myDiv');
myDiv.innerHTML=myDiv.innerHTML.replace(/(@[a-z0-9+)/gi,$1);
}
函数init()
{
文件。addEventListener('keydown',myKeyDown,false);
document.designMode=“on”;
}
window.onload=init;
这是我的变量名:@varname。如果我在这里打错了。。。
我的目标是在编辑时做一种语法高亮显示,高亮显示以@符号开头的变量名。但是,当我编辑文档的正文时,函数会运行,但在执行击键之前,光标会自动移动到正文的开头
我的假设是,keypress事件试图在指定的索引处插入新字符,但当我运行replace函数时,索引被弄乱了,因此它将字符插入点默认为开始
顺便说一下,我正在使用Firefox进行测试
任何帮助都将不胜感激
谢谢,
你的假设是正确的。使用
innerHTML
进行替换意味着浏览器必须扔掉div中的所有节点,并根据您提供的HTML字符串创建新节点,这意味着以前存在的选择中的节点不再存在。这是非常低效的,尤其是在每个按键上都这样做。您需要改用DOM方法来实现这一点
我建议在进行任何替换之前等待一段时间的键盘不活动,而不是在每次按键后进行
最后,这需要在哪些浏览器中工作
更新
我认为这是一个有趣的问题,所以我写了一个完整的解决方案。我也改变了使用innerHTML
的想法。在IE中保存和恢复所有其他浏览器的选择时,复杂的位是完全不同的方法。我还将其更改为使用contenteditable
,而不是designMode
。这排除了Firefox2,但它简化了一些事情,所以我希望这没问题
<script type="text/javascript">
function getBoundary(el, textNodes, charIndex) {
var charsSoFar = 0, textNodeLength;
// Walk text nodes
for (var i = 0, len = textNodes.length; i < len; ++i) {
textNodeLength = textNodes[i].data.length;
charsSoFar += textNodeLength;
if (charsSoFar >= charIndex) {
return {
node: textNodes[i],
offset: charIndex + textNodeLength - charsSoFar
};
}
}
throw new Error("Boundary not found");
}
function highlightVars() {
var myDiv = document.getElementById('myDiv');
var selectedRange, range, divText;
var selectionStartPos, selectionLength;
var hasRanges = !!(window.getSelection
&& document.createRange);
var hasTextRanges = !!(document.selection
&& document.body.createTextRange);
// Get the selection text position within the div
if (hasRanges) {
selectedRange = window.getSelection().getRangeAt(0);
range = document.createRange();
range.selectNodeContents(myDiv);
divText = range.toString();
range.setEnd(selectedRange.startContainer, selectedRange.startOffset);
selectionStartPos = range.toString().length;
selectionLength = selectedRange.toString().length;
} else if (hasTextRanges) {
selectedRange = document.selection.createRange();
range = document.body.createTextRange();
range.moveToElementText(myDiv);
divText = range.text;
range.setEndPoint("EndToStart", selectedRange);
selectionStartPos = range.text.length;
selectionLength = selectedRange.text.length;
}
// Substitute in existing text with vars highlighted
myDiv.innerHTML = divText.replace(/(@[a-z0-9_]+)/gi,
'<strong>$1</strong>').replace(/ $/, "\u00a0");
// Restore selection
if (hasRanges) {
var textNodes = [];
for (var n = myDiv.firstChild; n; n = n.nextSibling) {
textNodes.push( (n.nodeType == 1) ? n.firstChild : n );
}
var selectionStartBoundary = getBoundary(myDiv, textNodes,
selectionStartPos);
var selectionEndBoundary = getBoundary(myDiv, textNodes,
selectionStartPos + selectionLength);
range.setStart(selectionStartBoundary.node,
selectionStartBoundary.offset);
range.setEnd(selectionEndBoundary.node,
selectionEndBoundary.offset);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (hasTextRanges) {
range.moveToElementText(myDiv);
range.moveStart("Character", selectionStartPos);
range.collapse();
range.moveEnd("Character", selectionLength);
range.select();
}
}
var keyTimer;
function myKeyDown() {
if (keyTimer) {
window.clearTimeout(keyTimer);
}
keyTimer = window.setTimeout(function() {
keyTimer = null;
highlightVars();
}, 1000);
}
function init() {
var myDiv = document.getElementById("myDiv");
myDiv.onkeydown = myKeyDown;
}
window.onload = init;
</script>
<body>
<div id="myDiv" contenteditable="true">This is my variable
name: @varname. If I type here things go wrong...</div>
</body>
函数getBoundary(el、textNodes、charIndex){
var charsSoFar=0,textNodeLength;
//漫游文本节点
对于(变量i=0,len=textNodes.length;i=charIndex){
返回{
节点:textNodes[i],
偏移量:charIndex+textNodeLength-CharsFar
};
}
}
抛出新错误(“未找到边界”);
}
函数highlightVars(){
var myDiv=document.getElementById('myDiv');
变量selectedRange、range、divText;
变量selectionStartPos,selectionLength;
var hasRanges=!!(window.getSelection
&&document.createRange);
var hasTextRanges=!!(document.selection
&&document.body.createTextRange);
//获取div中的选择文本位置
if(hasRanges){
selectedRange=window.getSelection().getRangeAt(0);
range=document.createRange();
范围。选择节点内容(myDiv);
divText=range.toString();
range.setEnd(selectedRange.startContainer,selectedRange.startOffset);
selectionStartPos=range.toString().length;
selectionLength=selectedRange.toString().length;
}否则,如果(范围){
selectedRange=document.selection.createRange();
range=document.body.createTextRange();
range.moveToElementText(myDiv);
divText=range.text;
range.setEndPoint(“EndToStart”,selectedRange);
selectionStartPos=range.text.length;
selectionLength=selectedRange.text.length;
}
//用高亮显示的变量替换现有文本
myDiv.innerHTML=divText.replace(/(@[a-z0-9_239;]+)/gi,
“$1”)。替换(/$/,“\u00a0”);
//恢复选择
if(hasRanges){
var textNodes=[];
for(var n=myDiv.firstChild;n;n=n.nextSibling){
push((n.nodeType==1)?n.firstChild:n);
}
var selectionStartBoundary=getBoundary(myDiv、textNodes、,
选择开始位置);
var selectionEndBoundary=getBoundary(myDiv、textNodes、,
选择开始位置+选择长度);
range.setStart(selectionStartBoundary.node,
选择开始边界(偏移量);
range.setEnd(selectionEndBoundary.node,
selectionEndBoundary.offset);
var sel=window.getSelection();
选择removeAllRanges();
选择添加范围(范围);
}否则,如果(范围){
range.moveToElementText(myDiv);
范围。移动开始(“字符”,选择开始位置);
range.collapse();
range.moveEnd(“字符”,selectionLength);
range.select();
}
}
var键定时器;
函数myKeyDown(){
if(按键计时器){
窗口清除超时(键定时器);
}
keyTimer=window.setTimeout(函数(){
keyTimer=null;
highlightVars();
}, 1000);
}
函数init(){
var myDiv=document.getElementById(“myDiv”);
myDiv.onkeydown=myKeyDown;
}
window.onload=init;
这是我的变量
姓名:@varname。如果我在这里打错了。。。
我至少需要在IE和Firefox上使用它,但所有浏览器兼容性最好。不过,我不确定您使用DOM方法是什么意思。我需要这是一种语法高亮显示,意思是在用户键入特定单词后立即更改颜色或其他任何东西。这是一段非常令人印象深刻的代码。它可以很好地工作,但有一个小的例外:如果您键入一个文本字符串,并在末尾添加一个空格,然后键入另一个字符,则会用新字符覆盖该字符串末尾的空白。我想这和文件有关