一千萬個為什麽

搜索

嘗試修改onkeydown文檔的文本是錯誤地插入文本


我有以下html:

<html>
 <head>
   <script>

function myKeyDown()
{
    var myDiv = document.getElementById('myDiv');
    myDiv.innerHTML = myDiv.innerHTML.replace(/(@[a-z0-9_]+)/gi, '$1');
}

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>

我的目標是在編輯時進行一種語法高亮,以突出顯示以@符號開頭的變量名稱。但是,當我編輯文檔的正文時,該函數會運行,但在執行擊鍵之前,光標會自動移動到正文的開頭。

我的假設是keypress事件試圖在指定的索引處插入新字符,但是當我運行replace函數時,索引會搞亂,因此它將字符插入點默認為開頭。

我正在使用Firefox進行測試。

任何幫助,將不勝感激。

謝謝, B.J.

最佳答案

你的假設是正確的。使用 innerHTML 進行替換意味著瀏覽器必須丟棄div中的所有節點並從您提供的HTML字符串中創建新節點,這意味著之前存在的選擇節點不再存在。這是非常低效的,特別是在每個按鍵上都這樣做。您需要使用DOM方法來完成此操作。

我建議在進行任何替換之前等待一段時間的鍵盤不活動,而不是在每次按鍵後都這樣做。

最後,這需要使用哪些瀏覽器?

更新</強>

我認為這是一個有趣的問題,所以我寫了一個完整的解決方案。我也改變了使用 innerHTML 的想法。復雜的位是您必須使用的完全不同的方法,用於在IE中保存和恢復所有其他瀏覽器中的選擇。我還將其更改為使用 contenteditable 而不是 designMode 。這排除了Firefox 2,但它簡化了一些事情,所以我希望沒關系。

<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,
       '$1').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>

轉載註明原文: 嘗試修改onkeydown文檔的文本是錯誤地插入文本

猜你喜歡