JavaScriptは便利な機能をたくさん用意してくれてます。
それをVueはイベント修飾子という形で色々使いやすく用意してくれています。
今回はそんなイベント修飾子の解説です。
公式はこちら。
イベント修飾子は何がある?
Vueは全部で6つイベント修飾子を用意してくれています。
.stop
.prevent
.capture
.self
.once
.passive
一つずつ解説していきます。
.stop
これをつけるとバブリングを止めてくれます。
バブリングとは、子要素で発火したイベントが親要素でも効いちゃうってやつです。
具体的にバブリングを止めないとどうなるかというと、
子要素と親要素が両方clickイベントでの起こるメソッドを構えていた場合、
子要素でclickイベントが起こると、子要素のclickイベントでのメソッドの実行と同時に親要素のclickイベントのメソッドも実行されちゃう、という事象が起こります。
基本的にJavaScriptはイベントが発火されると、このバブリングの動きをして子から親へとイベントを伝播しちゃいます。
その伝播に対して「この先には伝播させない」と止めてくれるイベント修飾子が.stopになります。
ちなみにjsで用意されているevent.stopPropagation()をラッピングしています。
.prevent
こちらもよく使われるやつです。これはformのsubmitイベントに対して使うやつです。
form要素に送信先が指定されていない場合のデフォルトの動きをキャンセルしてくれます。
送信先が指定されていないデフォルトの動きとは、自身のURLに対して送信を行うというものです。
要は、送信先のURL指定がなければリロードしちゃうよって話ですね。
これをキャンセルしてくれます。
.preventをつけるとリロードせずに値を送信しますよーって感じです。
jsで言うところのevent.preventDefault()をラッピングしてます。
.capture
これはちょっとマニアックなやつです。
イベントの伝播をキャプチャフェーズで行うようにしてくれます。
まずは前提知識がいるのでマニアックな話を挟みます。
ざっくりとしか解説しないので、細かいところは各自調べていただけたらと思います。
まずJavaScriptはイベントを感知して色々行ってくれますが、このイベント実行にはいくつかフェーズと呼ばれるものがあります。
キャプチャフェーズ、ターゲットフェーズ、バブリングフェーズの3つです。
一番簡単なのはターゲットフェーズです。
これは、イベントが起こった場所を特定するっていうものですね。
このタグのこのイベントだな、となります。
次にバブリングフェーズです。
これは.stopの解説でも出てきましたが、イベントが発火するとターゲットフェーズで発火した場所が特定されます。
そしてそのイベントが起こった要素からどんどん親要素にイベントが伝播していきます。
上に上がっていくのがバブリングフェーズと覚えてください。(子:イベント発火箇所→親→さらに親→ルート)
そして最後が、キャプチャフェーズです。
これはバブリングフェーズとは反対に、ターゲットフェーズで特定した要素に向かって上から順番にイベントが伝播していきます。(ルート→親→子→孫:イベント発火箇所)
jsでは、ターゲットフェーズからバブリングフェーズにいくのが基本的な動きなんですが、
これをキャプチャフェーズの動きで実行させるというのが.captureです。
あんまり使う機会はないかもしれません。
以下の図がわかりやすいです。拾ってきました。
W3Cのドキュメントに載っていた図をお借りしました
実験してみたければ、Vueの動く環境で親要素と子要素両方にclickイベントを待たせておいて.stop
と組み合わせれば、親のメソッドだけ動くのがわかると思います。
<!-- 細かいのは端折ってます -->
<div>
<div id="myParent" v-on:click.capture.stop="onClickParent">
親要素
<div id="myElement" v-on:click.capture.stop="onClickChild">
子要素
</div>
</div>
</div>
<script>
~~~
methods: {
onClickParent() {
*console*.log('親要素のclickイベントが発火');
},
onClickChild() {
*console*.log('子要素のclickイベントが発火');
},
}
~~~
<script>
// クリックすると、「親要素のclickイベントが発火」とだけ表示される。
// .captureだけ消した状態でクリックすると、「子要素のclickイベントが発火」とだけ表示される。
ちなみに.captureはjsでいうと
event.addEventListener()で第3引数のuseCaptureにtrueを指定した時と同様の動作です。
.self
これは.stopと似ています。
イベントの伝播を制御してくれて、イベントが発生した要素でのみイベントハンドラーを実行します。
.stopとの違いは.stopは伝播を止めると言うのに近いので、2つ下の要素から伝播してきたものを自分のタイミングで止める、みたいな使い方もできちゃいますが.selfは自身しか実行しないので.stopよりも目的が限定的です。
jsでいうと、event.target
が自分自身の場合のみハンドラが呼び出されるという感じですね。
.once
一回だけ実行するよってやつです。一回実行すると構えているイベントでは使えなくなります。
これは余談になりますが、
よくハマる例として、ボタンの連打対策とかに.onceを使うというのがすぐに思いついたりするんですが、
バリデーションなどボタン押下するための条件を盛り込んでいると、バリデーションで引っかかると使えなくなるバグの原因になったりしますので注意です。
jsでいうと、event.addEventListener()の第3引数のoptionsに{ once: true }
を指定した時と同じ動きです。
.passive
スクロールイベントをスムーズにしてくれるやつです。
イベントの完了を待たずにスクロールしてくれるみたいですね。
注意点としては、.preventのイベント修飾子と同時に使うのは公式で非推奨なのでやめましょう。
.prevent
が無視されて警告が出ちゃうそうです。
これもjsではevent.addEventListener()の第3引数のpassiveに{ passive: true }
を指定した時の動きですね。
イベント修飾子の使い方
いつものv-onと同じ感覚で使います。
<v-btn @click.stop="methodA"></v-btn>
あとは、イベント修飾子はつなげて書くこともできます
<a @click.stop.prevent="methodB"></a>
イベント修飾子のみのパターンもあります。
<form v-on:submit.prevent></form>
おわり
使う機会がとてもたくさん、というわけではないですが、
絶対に知っておくべき便利なイベント修飾子のご紹介でした。
Vueが用意してくれてるのは知っていても、jsのどの機能なのかまで明記されているサイトは少なかったので今回盛り込んでおります。
よかったら参考にしてください
参考
・https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener
・https://developer.mozilla.org/ja/docs/Web/API/Event
・https://qiita.com/yokoto/items/27c56ebc4b818167ef9e
・https://johobase.com/vue-js-once-modifier/
・https://johobase.com/vue-js-capture-modifier/
・https://johobase.com/javascript-event-propagation/