DOMおれおれAdvent Calendar 2015 – 20日目

2015-12-20

イベント監視のコールバックでもらえるeventオブジェクト、色々使えます。

UIのデフォルト動作を止める

何と言っても event.preventDefault() が一番良く使われるかと思います。リンクで実装されてるけど見た目も動作もボタンていうね。(できるなら <button> で書いてほしい……。)

<a id="the-button" href="#">ここをクリック!</a>
var elButton = document.querySelector('a#the-button');
elButton.addEventListener('click', function(event) {
  // リンクの画面遷移をキャンセル
  event.preventDefault();

  // 何かボタンを押した際の処理……
});

ウェブページが持つUIは利用者の操作を受け付けて諸々の「デフォルト」動作を行うわけですが、それをキャンセルするのがこのメソッドです。(キャンセルっていう言い方で良いのかな。) 他にもこんなものをキャンセルできます。

  • チェックボックスのチェック
    • ただし change はキャンセルできない。もう値が変わった後だから
    • click はキャンセルできる。なおイベント発火時点の el.checked は更新後の値になるので、キャンセル後に戻る
  • フォームの送信
    • 入力内容を検証して、駄目ならキャンセルして「名前を入力してください」とか
    • 単純に入力完了として受け取って、結果をAjaxで送ったりとか
  • マウス操作全般
    • mousedown をキャンセルすると色々できなくなる
    • ドラッグ操作を実装するときキャンセルしないと、画面中の文字列が選択されたりとかする
    • 同じくフリック操作の実装時に。スクロールしちゃう
    • 昔は操作禁止とかでも使ったような。今ならCSSの pointer-events:none で事足りる

イベントの伝播を停止

こちらはそんなに多用する事はないと思うんだけど、時々使ったりします。

<div id="wrapper">
  <button id="button">Push!</button>
</div>
var elWrapper = document.querySelector('#wrapper');
elWrapper.addEventListener('click', function(event) {
  alert('Wrapper!');
});

var elButton = elWrapper.querySelector('#button');
elButton.addEventListener('click', function(event) {
  event.stopPropagation();
  alert('Button!');
});

普通にボタンをクリックすると “Button!” の次に “Wrapper!” とメッセージが表示されるんだけど、 event.stopPropagation() で伝播を止めているので、ラッパーの方は click イベントは発火しません。

イベントの伝播

イベントは「発火」した後、上位の要素へ順に伝わっていきます。今回の例ではボタンからラッパーの <div> へ、その後は <body><html> そして document へと昇ってゆきます。

それを止めるのが stopPropagation() で、実行すると今回のイベントは上位要素(ノード)へ通知されなくなります。

ちなみに “propagation” で「伝播(でんぱ)」の意味です。

ちなみにちなみに下方への伝達の仕組みもあるんだけど、あまり利用する機会ないので気にしなくて良いかなと思います。

他のイベントリスナーに通知しない

しれっと三つめ。 stopPropagation() は上位要素への伝播を止める機能でしたが、同じ要素で複数のコールバック関数を登録している際、他のコールバック関数の実行もまとめて止めるものがあります。

stopImmediatePropagation() です。

とはいえまあ、既に実行された分は止めようがないですね。コールバック関数は登録順に呼び出されるので、自分より後ろに並んでる関数は実行されなくなります。

環境

preventDefault() は各環境で問題ありません。

stopPropagation() 及び stopImmediatePropagation() は IE 9+です。IE 8の場合はコールバック関数で return false する事で伝播を止める事ができますが、この場合デフォルト動作のキャンセルも同時に行われてしまいます。

参考