イベントのキャプチャ、Bubbling、および委任



≪イベント|Events|ldap≫

  • イベント(event)は、Webブラウザに通知されたHTML要素を指すイベントである.
  • ページで使用されるJavaScriptは、これらのイベントに応答して特定の操作を実行することができる.
  • イベントハンドラ

  • イベントに反応するには、イベント発生時に実行される関数ハンドラを割り当てる必要があります.
  • HandlerはJavaScriptコードで、ユーザーの動作にどのように応答するかを記述しています.
  • addEventListener()メソッドを使用してイベントハンドラを登録します.
  • removeEventListener()メソッドを使用してイベントハンドラを削除します.
  • イベントバッファ


  • の要素にイベントが発生した場合、その要素に割り当てられたハンドラは操作を行い、その後親要素のハンドラが存在する場合は操作を実行します.このプロシージャは、最上位レベルの親要素に遭遇する前に繰り返し、各要素に割り当てられたハンドルによって操作されます.
  •       const outer = document.querySelector('.outer');
          const middle = document.querySelector('.middle');
          const button = document.querySelector('button');
    
          outer.addEventListener('click', (e) => {
            console.log(`${e.currentTarget}, ${e.target}`);
          });
    
          middle.addEventListener('click', (e) => {
            console.log(`${e.currentTarget}, ${e.target}`);
          });
    
          button.addEventListener('click', (e) => {
            console.log(`${e.currentTarget}, ${e.target}`);
          });
  • の上のコードでは、親順序がouther>meddle>ボタンであり、ログの出力順序がbutton、meddle、outerであることがわかります.
  • イベントバッファの停止

  • にイベント処理後の発泡停止を命じることもできる.
  • イベントオブジェクトのメソッドイベント.stopPropagation()とevent.stopImmediatePropagation()を使用します.event.stopPropagation()上のbundlingは防止できますが、同じ要素に複数のハンドルがある場合は、他のハンドルの動作を阻止できません.event.stopImmediatePropagation()同じ要素の特定のイベントでメソッドを実行するプロセッサのみが機能し、他のすべてのプロセッサは機能しません.
  • の発泡を停止しなければならない明らかな状況でなければ、発泡を阻止しないでください.アーキテクチャを考慮して本当に発泡を阻止しなければならない場合だけ、発泡を阻止することができます.
  •       const outer = document.querySelector('.outer');
          const middle = document.querySelector('.middle');
          const button = document.querySelector('button');
    
          outer.addEventListener('click', (e) => {
            // 메소들을 사용한 버블링 막기보다 안정적인 방법
            // 이벤트가 발생한 타겟과 현재 핸들러가 동작하는 타겟이 같은 경우가 아니면 아무동작없이 return
            if (e.currentTarget !== e.target) {
              return;
            }
    
            console.log(`${e.currentTarget}, ${e.target}`);
          });
    
          middle.addEventListener('click', (e) => {
            // 메소들을 사용한 버블링 막기보다 안정적인 방법
            // 이벤트가 발생한 타겟과 현재 핸들러가 동작하는 타겟이 같은 경우가 아니면 아무동작없이 return
            if (e.currentTarget !== e.target) {
              return;
            }
    
            console.log(`${e.currentTarget}, ${e.target}`);
          });
    
          button.addEventListener('click', (e) => {
            console.log(`${e.currentTarget}, ${e.target}`);
          });

    イベントのキャプチャ

  • イベントフローには3つのフェーズがあります.
  • 取得ステップ:イベントをサブエレメントに伝播するステップ
  • ターゲットステップ:イベントを実際のターゲット要素に転送するステップ
  • バブルフェーズ:イベントが親要素に伝播するフェーズ

  • には、tdをクリックすると、イベントが最上位から下へ伝播(キャプチャフェーズ)し、イベントがターゲット要素に到達して実行(ターゲットフェーズ)し、上へ伝播(Bublingフェーズ)することが示されている.これにより、要素に割り当てられたイベントハンドラが呼び出されます.
  • を使用してフェーズをキャプチャする必要がある場合は多くないため、bundlingフェーズでの論理処理がより一般的である.
  • 委任イベント

  • イベント委任は、同様の方法で複数の要素を処理する.
  • 委任
  • イベントは、各要素にハンドラを割り当てず、要素の共通の祖先に1つのイベントハンドラを割り当てるだけで、複数の要素を同時に処理できます.
  •       // Bad Code
          // 모든 자식요소에 이벤트리스너를 등록하여 메모리 낭비
          const lis = document.querySelectorAll('li');
    
          lis.forEach((el) => {
            el.addEventListener('click', () => {
              el.classList.add('selected');
            });
          });
    
          // Good Code
          // 이벤트 위임을 통한 강력한 핸들링
          const ul = document.querySelector('ul');
    
          ul.addEventListener('click', (e) => {
            // e.target을 통해 이벤트가 발생한 요소를 알 수 있다.
            if (e.target.tagName === 'LI') {
              e.target.classList.add('selected');
            }
          });

    参考資料

  • https://ko.javascript.info/introduction-browser-events
  • https://ko.javascript.info/bubbling-and-capturing
  • https://ko.javascript.info/event-delegation
  • https://velog.io/@nomadhash/Java-Script-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EA%B3%BC-%EC%BA%A1%EC%B3%90%EB%A7%81