プログラミング言語 Web関連 javascript JS イベント バブリングとイベント キャプチャ

JS イベント バブリングとイベント キャプチャ

 
 
JavaScript では、イベントが発生する順序を「イベント フロー」と呼びます.イベントをトリガーすると、一連の連鎖反応が発生します.たとえば、次のようなコードがあります。

 

 <body>
    <div id="wrap">
        <p class="hint">
            <a href="#">クリックしてください</a>
        </p>
    </div>
</body> 

タグごとにイベントが定義されている場合、 <a>タグをクリックすると、 <div><p>タグにバインドされたイベントもトリガーされることがわかります。この質問に答えるために、Microsoft と Netscape は、イベント キャプチャとイベント バブリングという 2 つの異なる概念を提案しました。

  • イベント キャプチャ: Microsoft Corporation によって提案された、イベントはドキュメント ルート ノード (ドキュメント オブジェクト) からターゲット ノードに流れ、途中でターゲット ノードの各親ノードを通過し、ターゲット ノードに到達するまでこれらのノードでキャプチャ イベントをトリガーします。イベントの;
  • イベント バブリング: Netscape によって提案されたもので、イベント キャプチャとは逆に、イベントはターゲット ノードからドキュメントのルート ノードに流れ、途中でターゲット ノードの親ノードを通過し、到達するまでこれらのノードでキャプチャ イベントをトリガーします。ドキュメント ノードのルート。全体のプロセスは、水中の気泡のようなもので、水の底から上に移動します。

ヒント: 上記のターゲット ノードは、イベントをトリガーするノードを指します。

その後、標準を統一するために、W3C は、次の図に示すように、イベント キャプチャとイベント バブリングを組み合わせるという妥協案を採用しました。

図: イベント キャプチャとイベント バブリング
図: イベント キャプチャとイベント バブリング (source: google.com)

イベントキャプチャ

イベント キャプチャ フェーズでは、イベントは DOM ツリーの最外層から開始され、ターゲット ノードの各親ノードを順番に通過し、イベントのターゲット ノードに到達するまで親ノードでイベントをトリガーします。上図のコードを例にとると、 <a>タグをクリックすると、 document -> div -> p -> aの順にイベントが<a>タグに渡されます。

サンプルコードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div id="wrap">DIV
        <p class="hint">P
            <a href="#">A</a>
        </p>
    </div>
    <script>
        function showTagName() {
            alert("事件捕获: " + this.tagName);
        }

        var elems = document.querySelectorAll("div, p, a");
        for (let elem of elems) {
            elem.addEventListener("click", showTagName, true);
        }
    </script>
</body>
</html> 

上記のコードを実行し、最も内側の<a>タグをクリックすると、実行結果が次の図に表示されます。

図: イベント キャプチャのデモ
図: イベント キャプチャのデモ

イベントバブリング

イベント バブリングは、イベント キャプチャとは正反対です。イベント バブリングは、ターゲット ノードから始まり、親ノードに沿って上昇し、水底の泡のように、ドキュメント ルート ノードまで親ノードでイベントをトリガーします。必ず上がります。

サンプルコードは次のとおりです。

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div onclick="alert('イベントバブリング:' + this.tagName)">DIV
        <p onclick="alert('イベントバブリング:' + this.tagName)">P
            <a href="#" onclick="alert('イベントバブリング:' + this.tagName)">A</a>
        </p>
    </div>
</body>
</html> 

上記のコードを実行し、最も内側の<a>タグをクリックすると、実行結果が次の図に表示されます。

図: イベント バブリングのデモ
図: イベント バブリングのデモ

イベントのキャプチャとバブリングを防ぐ

イベント キャプチャとイベント バブリングを理解すると、この機能が使いにくいことがわかります.たとえば、特定のノードにイベントをバインドし、クリックしたときにこのイベントをトリガーしたかった.その結果、イベント バブリングにより、イベントこのノードの子要素がトリガーされます。これを防ぐにはどうすればよいでしょうか。

イベントのキャプチャとイベントのバブリングを防ぐために、JavaScript で stopPropagation() メソッドが提供されます。構文は次のとおりです。

event.stopPropagation();

Note: stopPropagation() will prevent event capture and event bubbling, but it cannot prevent the default behavior of the label. たとえば、リンクをクリックすると、対応する Web ページを開くことができます。

サンプルコードは次のとおりです。

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div id="wrap">DIV
        <p class="hint">P
            <a href="#">A</a>
        </p>
    </div>
    <script>
        function showAlert(event) {
            alert("あなたは" + this.tagName + "タグをクリックしました。");
            event.stopPropagation();
        }

        var elems = document.querySelectorAll("div, p, a");
        for(let elem of elems) {
            elem.addEventListener("click", showAlert);
        }
    </script>
</body>
</html> 

In addition, you can also use the stopImmediatePropagation() method to prevent other event handlers for the same event on the same node. たとえば、特定のノードに対して複数のクリック イベントが定義されている場合、イベントがトリガーされると、これらのイベントはイベント ハンドラの 1 つが stopImmediatePropagation() メソッドを使用する場合、残りのイベント ハンドラは実行されません。

stopImmediatePropagation() メソッドの構文は次のとおりです。

event.stopImmediatePropagation();

サンプルコードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div onclick="alert('あなたは'+this.tagName+'タグをクリックしました')">DIV
        <p onclick="alert('あなたは'+this.tagName+'タグをクリックしました')">P
            <a href="#" id="link">A</a>
        </p>
    </div>
    <script>
        function sayHi() {
            alert("イベントの処理1");
            event.stopImmediatePropagation();
        }
        function sayHello() {
            alert("イベントの処理2");
        }
        //idがlinkのタグに複数のクリックイベントを定義する
        var link = document.getElementById("link");
        link.addEventListener("click", sayHi); 
        link.addEventListener("click", sayHello);
    </script>
</body>
</html> 
デフォルト アクションを防止する

特定のイベントには、リンクをクリックしたとき、指定したページに自動的にジャンプしたとき、送信ボタンをクリックしたとき、サーバーにデータを送信したときなど、デフォルトのアクションが関連付けられています。このようなデフォルト操作が発生することを望まない場合は、 preventDefault() メソッドを使用してそれを防ぐことができます. 構文は次のとおりです:

event. preventDefault();

サンプルコードは次のとおりです。

 <!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <a href="https://it-kiso.com/" id="link">リンク</a>
    <script>
        var link = document.getElementById("link");
        link.addEventListener('click', function(event){
            event.preventDefault(); // リンクのジャンプを防止する
        });
    </script>
</body>
</html> 

注: IE9 以下のバージョンは preventDefault() メソッドをサポートしていません。IE9 以下のブラウザーでは、 event.returnValue = false;を使用できます。

 

「 JS イベント バブリングとイベント キャプチャ」についてわかりやすく解説!絶対に観るべきベスト2動画

JavaScript でのバブリングとキャプチャ | JavaScript イベントのチュートリアル
JavaScript DOM チュートリアル #10 – イベント バブリング