bugfix> javascript > 投稿

HTMLを使用してコードエディタを作成しようとしています。

<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=Edge'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <link rel='stylesheet' href='style.css'>
</head>
<body>
    <pre id='editor'><code contenteditable='true'></code></pre>
    
    <script type='module'>
        import { highlight } from './highlighter.js';
        import { Caret } from './caret.js';
        (() =>
        {
            const editor = document.querySelector('#editor code');
            const caret = new Caret(editor);
            highlight(editor);
            editor.addEventListener('input', e =>
            {
                highlight(editor);
                e.preventDefault();
            });
            editor.addEventListener('keydown', e =>
            {
                const TAB   = 9;
                const ENTER = 13;
                switch (e.keyCode)
                {
                    // ...
                }
            });
        })();
    </script>
</body>
</html>

Highlighter.js:

import { Caret } from './caret.js';
export function highlight(editor)
{
    // ...
    const NORM = '#E6E6FA';
    // ...
    const Highlighter = {
        source: editor.innerText,
        start: 0,
        curr: 0,
        // ...
        fin()
        {
            return this.curr >= this.source.length;
        },
        advance()
        {
            return this.source[this.curr++];
        },
        // ...
        scan()
        {
            let result = '';
            this.start = this.curr;
            if (this.fin())
            {
                return null;
            }
            const char = this.advance();
            let color = NORM;
            switch (char)
            {
                // ...
            }
            return {
                color,
                text: this.source.substring(this.start, this.curr),
            };
        },
    };
    let result = '';
    const caret = new Caret(editor);
    const save = caret.getPos();
    for (;;)
    {
        const lexeme = Highlighter.scan();
        if (lexeme === null)
        {
            break;
        }
        const chars = lexeme.text.split('').map(
            x => `<span style='color: ${lexeme.color};'>${x}</span>`);
        result += chars.join('');
    }
    editor.innerHTML = result;
    caret.setPos(save);
};

基本的に、ユーザーのコードのテキストコンテンツを取得し、それをスキャンして色データを含む語彙素を生成し、それらの語彙素を文字に分割して、色付きのタグに入れ、それらのを文字列に追加します。エディターのinnerHTMLがに更新され、最後にユーザーのカーソルが適切な位置に戻されます。これは入力時に行われます。ただし、問題が1つあります。ユーザーの入力が速すぎると、入力したテキストが2倍になる可能性があります。私は他のタイプのイベントリスナーでこれを修正しようとし、setIntervalを使用してみましたが、まったくうまくいきませんでした。

回答 1 件
  • あなたが説明したことから

    if the user types too fast

    計算コストが高いことを確認します highlight() 関数は、への変更ごとに呼び出されます input 素子

    editor.addEventListener('input', e => {
      highlight(editor); // <--
      e.preventDefault();
    });
    
    

    私は提案しますデバウンスハイライトするためのその呼び出し。これがデバウンスの良い説明です。

    次のようなものを試してください。
    // Vanilla debounce: https://gist.github.com/peduarte/7ee475dd0fae1940f857582ecbb9dc5f
    function debounce(func, wait = 100) {
      let timeout;
      return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          func.apply(this, args);
        }, wait);
      };
    }
    // ...
    // adjust delay to find a balance between responsiveness and performance
    const delay = 500; 
    const runHighlight = () => highlight(editor);
    const debouncedHighlight = debounce(runHighlight, delay);
    editor.addEventListener('input', e => {
      e.preventDefault();
      debouncedHighlight();
    });
    
    

あなたの答え