イベントバブリング、イベントキャプチャ、イベント委任に基づく詳細な説明

イベントバブリング、イベントキャプチャ、イベント委任に基づく詳細な説明

イベントバブリング、イベントキャプチャ、イベント委任

JavaScript では、イベント委譲は非常に重要です。イベント委譲は、イベントのバブリングとキャプチャのメカニズムに依存しています。まず、イベントのバブリングとイベントのキャプチャについて説明します。

イベント バブリングは、現在トリガーされているイベント ターゲットから一度に 1 レベルずつ渡され、ドキュメントに到達するまで順番にトリガーされます。

イベントのキャプチャはドキュメントから開始され、実際のイベント ターゲットに到達するまで、一度に 1 レベルずつ下方に渡されます。

これは少し抽象的でしょうか? 実際、キーボードで入力するときと同じです。キーボードで入力しながら、コンピューターでも入力しているのでしょうか? 理解しやすいように例を挙げてみましょう。

<!DOCTYPE html>
<html>
    <ヘッド>
        <メタ文字セット="UTF-8">
        <タイトル></タイトル>
    </head>
    <スタイル タイプ="text/css">
        #box1 { 幅: 300px; 高さ: 300px; 背景: 青紫; }
        #box2 { 幅: 200px; 高さ: 200px; 背景: アクアマリン; }
        #box3 { 幅: 100px; 高さ: 100px; 背景: トマト; }
        div { オーバーフロー: 非表示; マージン: 50px 自動; }
    </スタイル>
    <本文>
        <div id="box1">
            <div id="box2">
                <div id="box3"></div>
            </div>
        </div>
        <スクリプト>
            関数 sayBox3() {
                console.log('最も内側のボックスをクリックしました');
            }
            関数 sayBox2() {
                console.log('中央のボックスをクリックしました');
            }
            関数 sayBox1() {
                console.log('一番外側のボックスをクリックしました');
            }
            // イベント監視、3 番目のパラメーターはブール値、デフォルトは false です。false はイベント バブリング、true はイベント キャプチャです。document.getElementById('box3').addEventListener('click', sayBox3, false);
            document.getElementById('box2').addEventListener('click', sayBox2, false);
            document.getElementById('box1').addEventListener('click', sayBox1, false);
        </スクリプト>
    </本文>
</html>

親子ボックスである 3 つのボックスを描画しました。各ボックスは印刷イベントにバインドされています。中央の赤いボックスをクリックしてみましょう。

赤いボックスをクリックしただけなのに、緑と紫のボックスも印刷イベントをトリガーしていることがわかりました。違反の順序は、赤 > 緑 > 紫でした。この現象はイベント バブリングです。

もう一度イベントキャプチャを試してみましょう。上記のコードのイベントリスナーの 3 番目のパラメータを true に変更し、赤いボックスをクリックします。

中央の赤いボックスだけをクリックします。前回と同様に、3 つのボックスすべてでイベントがトリガーされますが、順序は逆になります。紫 > 緑 > 赤です。この現象はイベント キャプチャと呼ばれます。

上記の例から、イベント バブリングとイベント キャプチャリングを簡単に理解できるはずです。通常、バブリングはデフォルトで使用され、バブリングはルート ドキュメントまで続きます。

ここで、イベント委任 (イベント プロキシとも呼ばれます) について説明します。一般的な例を使って説明しましょう。

月曜日に 3 人の同僚が宅配便を受け取る予定です。宅配便に署名する方法は 2 つあります。1. 3 人が会社のゲートで宅配便を待つ。2. フロント デスクの MM に代理で署名を依頼する。実際には、ほとんどの企業は委任ソリューションを採用しています (会社は、速達便を待つためにドアの前に立っている従業員をそれほど多くは容認しません)。フロントデスクの MM がエクスプレスを受け取った後、受取人が誰であるかを判断し、受取人の要件に従って署名し、受取人に代わって支払いも行います。このソリューションには、会社に新しい従業員がいても(人数に関係なく)、フロントデスクの MM が新しい従業員に送られた速達便を受け取った後に確認して署名するという利点もあります(イベントは、一時的に存在しないノードにバインドすることもできます)。

別の例を見てみましょう。

現在、ul があり、ul には 100 li があります。これらの 100 li にクリック イベントをバインドします。通常は for ループを使用してバインドできますが、1000 li がある場合はどうなるでしょうか。 効率と速度を向上させるために、この時点でイベント委任を使用して、ul に 1 つのイベントのみをバインドできます。イベント バブリング ルールに従って、ul 内の各 li をクリックする限り、ul のバインドされたイベントがトリガーされます。ul バインディング イベントの機能でのいくつかの判断を通じて、これらの 100 li のクリック イベントをトリガーできます。

具体的な実装方法については、コードを参照してください。

// ここではIEについては触れません。最後に説明します。 function clickLi() {
    alert('liをクリックしました');
}
document.getElementById('isUl').addEventListener('click', function(event) {
    // 各関数にはイベント オブジェクトがあり、そのオブジェクトにはイベント ソースを指す target 属性があります。var src = event.target;
    // ターゲットイベントソースノード名が li であると判断して、この関数を実行します // ターゲットには、ID 名、クラス名、ノード名など、多くの属性があります。if (src.nodeName.toLowerCase() == 'li') {
       クリックLi();
    }
});

このように、クリック イベントを ul にバインドすると、すべての li が関数をトリガーします。

異なる関数を異なる li にバインドしたい場合はどうすればよいでしょうか?

3 つの li があると仮定します。最初に 3 つの異なる関数を記述し、次に 3 つの li に異なる ID 名を設定します。その後、ID 名が正しいかどうかを判断することで、異なる関数を異なる li にバインドできます。

<本文>
    <ul id="isUl">
        <li id="li01">1</li>
        <li id="li02">2</li>
        <li id="li03">3</li>
    </ul>
    <スクリプト>
        関数clickLi01() {
            alert('最初のliをクリックしました');
        }
        関数clickLi02() {
            alert('2番目のliをクリックしました');
        }
        関数clickLi03() {
            alert('3番目のliをクリックしました');
        }
        document.getElementById('isUl').addEventListener('click', function(event) {
            var srcID = イベントターゲットID;
            if(srcID == 'li01'){
                クリックLi01();
            }そうでない場合(srcID == 'li02') {
                クリックLi02();
            }そうでない場合(srcID == 'li03') {
                クリックLi03();
            }
        });
    </スクリプト>
</本文>

これはいわゆるイベント委任であり、親要素をリッスンすることでイベントをさまざまな子要素にバインドし、リッスン回数を減らして速度を向上させます。

では、要素のイベント バブリングを防ぐことはできるのでしょうか? 答えは「はい」です。

冒頭の例では、最も内側の赤いボックスだけをクリックし、他の 2 つのボックスのイベントをトリガーしたくない場合は、イベントを赤いボックスにバインドする関数に次のように記述できます。

関数 sayBox3(イベント) {
    // バブリングを停止する event.stopPropagation();
    console.log('最も内側のボックスをクリックしました');
}
document.getElementById('box3').addEventListener('click', sayBox3, false);

このように、赤いボックスをもう一度クリックすると、そのボックス自体のイベントのみがトリガーされます。

では、泡立ちを防ぐ実用的な用途はあるのでしょうか?答えは「はい」です。次の例を見てみましょう。

これはモーダル ボックスです。現在の要件は、赤いボタンをクリックするとページにジャンプし、応答なしで白いダイアログ ボックスをクリックし、他の場所をクリックしてモーダル ボックスを閉じる必要があることです。

ここでは、バブリングを防止する方法を使用する必要があります。赤いボタンは白いダイアログボックスの子要素であり、白いダイアログボックスはモーダルボックス全体の子要素です。モーダルボックスを閉じるためのクリックイベントを追加し、赤いボタンにクリックイベントジャンプを追加します。すると問題が発生します。白いダイアログボックスがクリックされている限り、バブリングメカニズムによりモーダルボックスも閉じられます。実際、白いダイアログボックスをクリックしても反応は必要ありません。このとき、白いダイアログボックスにクリックイベントをバインドし、関数にevent.stopPropagation();と記述します。これで完了です。

IEについて

古いバージョンの IE には互換性の問題があり、addEventListener() と removeEventListener() をサポートしていません。独自のリスニング メソッドがあります。

// イベントを追加します。イベントフローはバブリングに固定されます。attachEvent(イベント名、イベント処理関数)
// イベントの削除 detachEvent(イベント名, イベント処理関数)

また、IE のイベント オブジェクトは window.event、イベント ソースは srcElement であり、バブリングを防止する方法も異なります。

関数() {
    // IE でのバブルを防止します。window.event.cancelBubble = true;
    // IE でイベント ソース ID を取得する
    var srcID = window.event.srcElement.id;
}
関数(イベント) {
    // IE 以外のイベントでのバブルを防止します。event.stopPropagation();
    // IE以外のイベントソースIDを取得する
    var srcID = イベントターゲットID;
}

補充する

jsのブラウザ互換性の問題に関しては、一般的には機能検出、if(){}else{}によって解決されます。

私たちは日常業務で jQuery を使用することが多いのですが、IE はこうした特殊なケースでもすでに互換性を実現しています。

jQuery バージョン 1.7 以降、最も人気のあるイベント監視メソッドは $(要素).on(イベント名、実行関数) です。また、イベント委任メソッド $(委任先の要素).on(イベント名、委任先の要素、実行関数) もあります。

最後に、要素のバブリングが禁止されている場合は、イベント委任を使用してイベントをリッスンしないでください。イベント委任の原則は、イベント バブリングを使用することです。バブリングが禁止されている場合、イベントをリッスンすることはできません。

上記は私の個人的な経験です。参考になれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript におけるイベント委譲メカニズムと深いコピーと浅いコピーの簡単な分析
  • JavaScript イベント委任の実装の原則と利点
  • JavaScript イベント監視とイベント委任の例の詳細な説明
  • js のイベント オブジェクトとイベント委任の概要
  • JavaScriptはイベントリスナーをイベント委任にバッチで追加します。詳細なプロセス

<<:  Navicat は CSV データを MySQL にインポートします

>>:  Linuxでファイルの作成時間を表示する方法

推薦する

CSS で要素を中央揃えにする N 通りの方法

目次序文インライン要素の中央揃えテキストを垂直に中央揃え要素を水平方向に中央揃えにするブロックレベル...

JavaScript 戦略パターンを使用してフォームを検証する方法

目次概要戦略パターンを使用しないフォーム検証戦略パターンを使用して最適化する戦略パターンの利点要約す...

docker compose デプロイメントにおけるマスタースレーブレプリケーションの実装

目次構成解析サービス構築ディレクトリ構造ファイルを作成インスタンス構成サービスを開始するテストRed...

Vue は動的なプログレスバー効果を実現します

この記事では、動的なプログレスバー効果を実現するためのVueの具体的なコードを例として紹介します。具...

MySQL 8.0.12 のインストールと環境変数の設定チュートリアル (Win10 の場合)

Windows 10 プラットフォームでの MySQL のインストール、構成、起動、ログイン、環境...

Linux カーネル デバイス ドライバー Linux カーネル 基本メモの概要

1. Linuxカーネルドライバモジュールの仕組み静的ロードでは、ドライバモジュールをカーネルにコン...

WeChatアプレットのスクロールビューの改行問題を解決する

今日、小さなプログラムを書いていたときに、スクロールビューを使用したのですが、スクロールビュー内のテ...

HTM と HTML の違いは何ですか? HTM と HTML の違いは何ですか?

Web デザインを学習する過程で、html と htm の関係など、遭遇した多くの問題について深く...

CSS3はさまざまな境界効果を実現します

半透明の境界線結果: 実装コード: <div> 半透明の境界線が見えますか? </...

MySQL における大規模オブジェクトのマルチバージョン同時実行制御の詳細な説明

MySQL 8.0: InnoDB のラージ オブジェクトに対する MVCCこの記事では、MySQL...

MySQL の JSON 挿入の問題

MySQL 5.7.8 以降では、JSON テキストでデータを効率的に取得できるネイティブ JSON...

Linux学習におけるmkdirコマンドの詳しい説明

目次序文1. ファイルの概念に関する基礎知識2. mkdir コマンド序文最近、Linux にますま...

IE8互換表示(IE7モード)とスタンドアロンIE7の違いの詳細な説明

1つ。 IE8 互換表示の概要<br />新しいバージョンのブラウザが古い Web サイ...

MySQL パスワード変更方法の概要

MySQL 5.7 より前のバージョンのパスワードを変更する方法:方法1: SET PASSWORD...

MySQL のデータ型とフィールド属性の原理と使用法の詳細な説明

この記事では、MySQL のデータ型とフィールド属性について説明します。ご参考までに、詳細は以下の通...