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

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

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

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でファイルの作成時間を表示する方法

推薦する

HTML マークアップ言語 - フォーム

123WORDPRESS.COM HTML チュートリアル セクションに戻るには、ここをクリックして...

Idea は、Web プロジェクトを開始するように Tomcat を設定します。グラフィック チュートリアル

tomcatの設定1. 実行構成をクリック 2. tomcat localを選択 3. tomcat...

Vueナンバープレート検索コンポーネントの使い方の詳しい説明

参考までに、シンプルなナンバープレート入力コンポーネント(vue)です。具体的な内容は次のとおりです...

MySQL アカウント情報をエレガントにバックアップする方法

序文:最近、インスタンスの移行の問題に遭遇しました。データの移行後、データベースのユーザーと権限も移...

DockerにRabbitMQを素早くインストールする方法

1. 画像を取得する #Webコントロールページを含むバージョンを指定します docker pull...

さまざまな環境での Docker Compose のインストール方法

1. オンラインインストール現在、Linux x86アーキテクチャのオンラインインストールのみを試し...

mysql5.6.zip形式の圧縮版インストールグラフィックチュートリアル

はじめに: MySQL は、スウェーデンの MySQL AB によって開発されたリレーショナル デー...

Docker Gitlab+Jenkins+Harborは永続的なプラットフォーム運用を構築します

CI/CD の概要CIワークフロー設計Gitコードバージョン管理システムはコマンドラインでのみ管理で...

JavaScript データのフラット化の詳細な説明

目次フラット化とは何か再帰トストリング減らすアンダーコア_.平坦化_。連合_。違い要約するフラット化...

Linux システムでの gcc コマンドの使用法の詳細な説明

目次1. 前処理2. コンパイル3. コンパイル4. リンク1. gccのインストール(Ubuntu...

Dockerfile をベースに Zabbix 監視システムのコード例を作成する

forループを使用してZabbixイメージをコンテナにインポートします。 n を `ls *.tar...

Linuxパフォーマンス監視コマンドの簡単な紹介

システムでさまざまな IO ボトルネック、メモリ使用量の増加、CPU 使用率の増加などの問題が発生し...

Linux カーネル デバイス ドライバー 高度な文字デバイス ドライバーのメモ

/****************** * 高度な文字デバイス ドライバー ***********...

Hadoop 3.2.0 クラスターの構築に関する一般的な考慮事項

1つのポートの変更バージョン 3.2.0 では、ネームノード ページ ポートは 9870、データノー...

SeataがMySQL 8バージョンを使用できない問題を解決する方法

考えられる理由: Seata が MySQL 8 をサポートしない主な理由は、接続ドライバーがバージ...