JS event delegation (event proxy)

JS イベント委任 (イベント プロキシ)

 
 
JS イベント バブリングを使用してイベントを要素に動的にバインドする方法は、イベント デリゲーション (イベント デリゲーション、「イベント プロキシ」とも呼ばれます) と呼ばれ、JavaScript で最も一般的なテクノロジの 1 つです。

 

event delegationとは、子要素にバインドする必要があるイベント (onclick、onkeydown など) をその親要素に委任し、親要素に子要素のバブリング イベントを監視させ、子要素が呼び出されたときにこのイベントを見つけることです。泡立つ子要素。

簡単な例を挙げると、寮の学生全員が宅配便を受け取る必要があります.1つの方法は、宅配便を1人ずつピックアップするように依頼し、それを持ち帰り、寮の学生に1人ずつ配布することです.受信者によると。ここでは、速達をイベントと見なすことができます。各学生は、イベントにバインドする必要がある DOM 要素です。寮長は、これらの DOM 要素の親要素であり、イベントはこの親要素にバインドする必要があります。によると、受取人がクーリエを配布するプロセスは、イベント実行のプロセスです。

event delegationを使用する理由

JavaScript では、ページ上のイベント ハンドラーの数がページの全体的なパフォーマンスに直接影響します。これは、各イベント ハンドラーがオブジェクトであり、オブジェクトがメモリを占有するためです。メモリ内のオブジェクトが多いほど、ページのパフォーマンスが低下します。 .さらに、イベント ハンドラーは DOM ノードと対話する必要があり、DOM にアクセスする回数が増えるほど、ブラウザーの再描画とリフローが発生し、ページのパフォーマンスに影響を与えます。

再描画とは、要素のスタイルが変更されたときに、ブラウザーが要素の新しいスタイルに従って要素の外観を再描画することを意味します。リフローとは、DOM ツリーの一部が変更された場合 (たとえば、要素のサイズが変更された場合)、ブラウザーが DOM ツリーを再作成することを意味します。

ページ内の多くのテーブルまたはリストにイベントを追加する必要がある場合、それらを 1 つずつ追加するのは面倒ですが、event delegationを使用すると、作業負荷が大幅に軽減され、ページのパフォーマンスが向上します。

event delegationの原則

event delegationは、イベントのバブリングの原則を使用して実装されます。これは、大まかに次の 3 つのステップに分けることができます。

  1. イベント要素を追加する親要素を決定します。
  2. 親要素のイベントを定義し、子要素のバブリング イベントをリッスンします。
  3. event.target を使用して、イベント バブリングをトリガーする子要素をターゲットにします。

注: event delegationを使用する場合、イベントが親要素に委任されるわけではありません。イベントのバブリングの処理にも時間がかかるため、距離が遠くなるほど時間がかかるため、直接の親要素でイベント委任を使用するのが最適です。

ul リストの下の各 li タグにクリック イベントを追加する場合、event delegationを使用しない場合、最も簡単な方法は、ループを使用して各 li タグにイベントをバインドすることです. サンプル コードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            var the_li = the_ul.getElementsByTagName('li');
            for( var i=0; i < the_li.length; i++ ){
                the_li[i].onclick = function(){
                    console.log(this.innerHTML)
                }
            }
        }
    </script>
</body>
</html> 

上記のコードからわかるように、各 li タグのクリック イベントをバインドするには、まず ul タグを見つけ、次に ul タグを介してすべての li タグを見つけ、最後にすべての li タグをトラバースしてイベントをバインドする必要があります。 .イベントの委任を使用すると、はるかに簡単になります。サンプル コードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            the_ul.onclick = function(e){
                console.log(e.target.innerHTML)
            }
        }
    </script>
</body>
</html> 

event delegationを使用する場合、ul タグにイベントをバインドするだけでよいことがコードからわかります.li タグをクリックすると、イベント バブリングの特性により、ul タグのイベントがトリガーされます.クリックされたliタグを見つけるために、イベントのターゲット属性にイベントオブジェクトを渡す必要があります。ただし、これには欠点もあります。つまり、ul タグをクリックすると、イベントもトリガーされます。

さらに、li タグを ul タグに動的に追加する必要があり、新しく追加された li タグにクリック イベントを追加する必要がある場合は、イベント デリゲーションを通じて実装する必要があります。サンプル コードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list" style="width: 100px;margin:0;float: left;">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <button style="float:left;" id="addli">liを追加</button>
    <button style="float:left;" id="delli">liを削除</button>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            var the_li = the_ul.getElementsByTagName('li');
            var sum = the_li.length
            the_ul.onclick = function(e){
                console.log(e.target.innerHTML)
            };
            document.getElementById('addli').onclick = function (){
                var newli = document.createElement("li");
                newli.innerHTML = ++sum;
                the_ul.appendChild(newli);
            };
            document.getElementById('delli').onclick = function (){
                the_ul.firstElementChild.remove();
            };
        }
    </script>
</body>
</html> 

event delegationの利点

1) メモリ消費を減らす

event delegationを使用すると、多くのメモリを節約でき、イベントの定義を減らすことができます. 上記の例から、ul タグの下のすべての li タグにクリック イベントを追加するには、各 li タグのイベントを個別にバインドすると、書くのが面倒なだけでなく、大量のメモリを消費します。イベント デリゲーションを使用してクリック イベントを ul タグにバインドすることで、簡潔で効率的なすべての li タグを監視できます。

2) イベントを動的にバインドする

Web ページでは、上記の例で li タグを ul タグに動的に追加するなど、ページ上の要素を動的に追加または削除する必要がある場合があります。event delegationを使用しない場合は、新しい要素を追加し、同時に削除された要素のイベントをアンバインドします。 ulタグでliタグを増やすにしても減らすにしても、イベントデリゲーションを使うのはそれほど面倒ではない、つまり、新しく追加した要素に対してイベントをバインドする必要はなく、削除した要素に対してイベントをバインド解除する必要もない要素。

そのため、event delegationを使用してイベントを動的にバインドすると、多くの反復作業を減らすことができます。

要約する

event delegationを使用するには、イベントがバブルできるようにする必要があります。イベント委任の使用に適したイベントには、クリック、マウスダウン、マウスアップ、キーダウン、キーアップ、キープレスなどがあります。 mouseover および mouseout イベントもイベントのバブリングを引き起こす可能性があることに注意してください。これは処理が非常に面倒であるため、mouseover および mouseout イベントでイベント委譲を使用することはお勧めしません。

また、イベント バブリングを発生させないイベント (ロード、アンロード、アボート、フォーカス、ブラーなど) には、event delegationを使用できません。

 

「 JS event delegation (イベント プロキシ)」についてわかりやすく解説!絶対に観るべきベスト2動画

What is Event Delegation? – JavaScript DOM Tutorial For Beginners
Event Delegation in JavaScript Explained in 5 Minutes