Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/411.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 尝试修改文档的文本onkeydown会错误地插入文本_Javascript_Html - Fatal编程技术网

Javascript 尝试修改文档的文本onkeydown会错误地插入文本

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:

<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方法是什么意思。我需要这是一种语法高亮显示,意思是在用户键入特定单词后立即更改颜色或其他任何东西。这是一段非常令人印象深刻的代码。它可以很好地工作,但有一个小的例外:如果您键入一个文本字符串,并在末尾添加一个空格,然后键入另一个字符,则会用新字符覆盖该字符串末尾的空白。我想这和文件有关