【JavaScript】イベントの中止 - preventDefault / stopPropagation / stopImmediatePropagation

【JavaScript】イベントの中止 - preventDefault / stopPropagation / stopImmediatePropagation

JavaScriptのブラウザイベントにおけるイベントの中止について解説します。

検証環境

イベントの中止

Eventオブジェクトにはイベントを中止するメソッドが備わっています。

リンクの規定動作を中止するメソッドやイベントの伝搬を中止するメソッドなど種類があります。

このドキュメントでは次の3つのメソッドについて解説します。

  • preventDefault
  • stopPropagation
  • stopImmediatePropagation

規定動作の中止(preventDefault)

規定動作の中止にはpreventDefaultメソッドを使用します。

規定動作とは例えばリンクのページ遷移やチェックボックスのチェックです。

基本構文

Eventオブジェクト.preventDefault()

サンプル

<style>
    #log {
        border: 1px solid black;
        padding: 5px;
    }
</style>

<main id="main">
    <div id="div">
        <input id="checkbox" type="checkbox">
        <a id="link" href="https://it-hack.net/">TOPページ</a>
    </div>
</main>
<pre id="log"></pre>
<button id="btn">リセット</button>


<script type="text/javascript">

    function logger( text ) {
        let log = document.getElementById('log');
        log.textContent += text +  "\n";
    }
    
    function reset( event ) {
        let log = document.getElementById('log');
        log.textContent = "";
    }
    
    let btn = document.getElementById('btn');
    btn.addEventListener('click', reset);
    
    let main = document.getElementById('main');
    main.addEventListener('click', function() {
        logger("Main Event.");
    });

    let div = document.getElementById('div');
    div.addEventListener('click', function() {
        logger("Div Event.");
    });

    let checkbox = document.getElementById('checkbox');
    checkbox.addEventListener('click', function( event ) {
        logger("Checkbox Event.");
        ___ih_hl_start
        event.preventDefault();
        ___ih_hl_end
    });
    
    let link = document.getElementById('link');
    link.addEventListener('click', function (event) {
        logger("Link Event.");
        ___ih_hl_start
        event.preventDefault();
        ___ih_hl_end
    });

</script>

チェックボックスのクリックイベント(43〜47行目)、リンクのクリックイベント(49〜53行目)はpreventDefaultメソッドを呼び出します。

また、イベントの伝搬を確認するため親要素(maindiv)にもイベントハンドラーを登録しました。

プレビューのチェックボックスをクリックしてもチェックマークは付かず、リンクをクリックしてもページが変わることはありません。

また、各イベントハンドラーはテキストを表示しますが、その順番からイベントは伝搬していることが分かります。

※ リセットボタンをクリックするとテキストをリセットします。

なお、preventDefaultメソッドで規定動作を中止するにはEventオブジェクトのcancelableプロパティがtrueである必要があります。

イベント伝搬の中止(stopPropagation)

イベント伝搬の中止にはstopPropagationメソッドを使用します。

基本構文

Eventオブジェクト.stopPropagation()

サンプル

<style>
    #log {
        border: 1px solid black;
        padding: 5px;
    }
</style>

<main id="main">
    <div id="div">
        <input id="button" type="button" value="確認">
    </div>
</main>
<pre id="log"></pre>
<button id="btn">リセット</button>


<script type="text/javascript">

    function logger( text ) {
        let log = document.getElementById('log');
        log.textContent += text +  "\n";
    }
    
    function reset( event ) {
        let log = document.getElementById('log');
        log.textContent = "";
    }
    
    let btn = document.getElementById('btn');
    btn.addEventListener('click', reset);
    
    let main = document.getElementById('main');
    main.addEventListener('click', function() {
        logger("Main Event.");
    });

    let div = document.getElementById('div');
    div.addEventListener('click', function() {
        logger("Div Event (1).");
        ___ih_hl_start
        event.stopPropagation();
        ___ih_hl_end
    });
    div.addEventListener('click', function () {
        logger("Div Event (2).");
    });

    let button = document.getElementById('button');
    button.addEventListener('click', function( event ) {
        logger("Button Event.");
    });

</script>

main要素、div要素、input要素にクリックイベントハンドラーを登録しています。

div要素には2つ登録しており、1個目(38〜41)はstopPropagationメソッドを呼び出します。

プレビューの確認ボタンをクリックすると、各イベントハンドラーが実行され、テキストが表示されますが、main要素のテキストは表示されません。

このことからdiv要素のクリックイベントでイベントの伝搬が止まっていることが確認できます。

また、div要素の2個目のイベントハンドラーは実行されていますが、このメソッドも中止するには次のstopImmediatePropagationメソッドを使用します。

イベント伝搬の即時中止(stopImmediatePropagation)

イベント伝搬の即時中止にはstopImmediatePropagationメソッドを使用します。

ここで言う『即時中止』とは、同じ要素(オブジェクト)のイベントハンドラーも中止するという意味です。

同じ要素(オブジェクト)に複数のイベントハンドラーを登録した場合、stopPropagationメソッドはそれらを実行し、親へのイベント伝搬を中止します。

対してstopImmediatePropagationメソッドは呼び出すと、他の呼び出されていないイベントハンドラーから中止します。

基本構文

Eventオブジェクト.stopImmediatePropagation()

サンプル

<style>
    #log {
        border: 1px solid black;
        padding: 5px;
    }
</style>

<main id="main">
    <div id="div">
        <input id="button" type="button" value="確認">
    </div>
</main>
<pre id="log"></pre>
<button id="btn">リセット</button>


<script type="text/javascript">

    function logger( text ) {
        let log = document.getElementById('log');
        log.textContent += text +  "\n";
    }
    
    function reset( event ) {
        let log = document.getElementById('log');
        log.textContent = "";
    }
    
    let btn = document.getElementById('btn');
    btn.addEventListener('click', reset);
    
    let main = document.getElementById('main');
    main.addEventListener('click', function() {
        logger("Main Event.");
    });

    let div = document.getElementById('div');
    div.addEventListener('click', function() {
        logger("Div Event (1).");
        ___ih_diff_start
-        event.stopPropagation();
+        event.stopImmediatePropagation();
        ___ih_diff_end
    });
    div.addEventListener('click', function () {
        logger("Div Event (2).");
    });

    let button = document.getElementById('button');
    button.addEventListener('click', function( event ) {
        logger("Button Event.");
    });

</script>

stopPropagationメソッドのサンプルのstopPropagationメソッドをstopImmediatePropagationメソッドに変更しました。

プレビューの確認ボタンをクリックし、表示テキストの内容から、先ほどとは変わり2個目のdiv要素のイベントハンドラーが実行されていないことが確認できます。

これは1個目でstopImmediatePropagationメソッドが呼び出されたため、以降のイベントハンドラーが中止されたためです。