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

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

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

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

推薦する

Vueはフィルターを使用して日付をフォーマットします

この記事では、フィルターを使用して日付をフォーマットするVueの具体的なコードを参考までに紹介します...

コピー&ペーストはパッケージングの敵です

OO、デザイン パターン、および多くのオブジェクト指向の原則について話す前に、まず 1 つのことを習...

Unix/Linuxフォークの隠れたオーバーヘッド

目次1. フォークの起源2. 初期のUNIXオーバーレイ技術3. UNIXに導入される前のフォークの...

VMwareでCentOSがインターネットにアクセスできない問題を素早く解決

昨日、VMware に CentOS7 をインストールしました。Tomcat パッケージを転送するた...

Docker の Windows ストレージ パス設定操作

Windows 10 に Docker をインストールする場合、コンテナタイプを Linux コンテ...

MySQLのあいまいクエリインデックスの失敗の問題を解決するいくつかの方法

% ワイルドカードを使用すると、インデックス失敗の問題が発生することがよくあります。ここでは、lik...

Mac ノードの削除と再インストールのケーススタディ

Macノードの削除と再インストール消去 ノード -v sudo npm アンインストール npm -...

Linux でのソース パッケージ インストールのサービス管理

目次1. ソースパッケージサービスの起動管理2. ソースパッケージサービスのセルフスタート管理3. ...

Centos8 は kdc 暗号化に基づいて nfs を構築します

目次構成nfs サーバー (nfs.skills.com) nfs クライアント (client.s...

JavaScript によるダイナミッククリスマスツリーの詳細な説明

目次1. CSS のみを使用して作成したアニメーションのクリスマスツリー2. CSS のみを使用して...

MYSQLテーブルの包括的な概要

目次1. テーブルを作成する1.1. テーブルを作成するための基本構文1.1.1. シンプルなテーブ...

WeChatアプレットのスクロールビューは、プルアップ時にデータの読み込みを重複させるソリューションを実装しています。

WeChat アプレットのスクロール ビューでは、プルアップして読み込むときにバグが多く発生します...

Windows での MySQL スケジュールバックアップ スクリプトの実装

Windows サーバーでデータベース データを定期的にバックアップする場合は、Windows タス...

html リンク タグ タイトル属性 改行 マウス ホバー プロンプト コンテンツ 改行効果

オブジェクト上にマウスを移動したときにコンテンツ(タイトル属性の内容)を折り返す方法、HTML タイ...