前回の記事では.self修飾子を使用して、イベントが発生した要素だけでイベントが処理されるようにする方法について紹介しました。
前々回の記事では.stop修飾子を使用して、イベントの伝播を抑制する方法についてご紹介しました。
JavaScriptのイベントは、イベントが発生した要素のみではなく、要素が配置されている親の要素や、要素内に配置した子要素でも発生します。
イベントが発生するフェーズには、キャプチャフェーズ、ターゲットフェーズ、バブリングフェーズの3つがあります。
クリックなどのユーザーの操作を要素が受け付けると、ユーザーが操作したイベントの発生元の要素でターゲットフェーズが実行されてイベントが発生します。
そしてその後に、イベントの発生元の要素からDOM要素を上位にたどって、順にイベントが発生するバブリングフェーズが実行されます。
Webページの最上位であるwindowオブジェクトから下位のイベントの発生元の要素までたどってイベントを発生させるキャプチャフェーズは、JavaScriptの既定のイベント発生の動作では実行されません。
しかしVue.jsには、このイベントが処理される順序を変更するための方法が用意されています。
そこで今回は、v-onディレクティブでイベントを処理する際に、処理の順序を変更しキャプチャフェーズでイベントが処理されるようにするために使用する.capture修飾子について紹介します。
JavaScriptが発生するフェーズの「キャプチャフェーズ、ターゲットフェーズ、バブリングフェーズ」については、以下の記事にまとめていますので合わせてご覧ください。
目次
v-onディレクティブの.capture修飾子
.capture修飾子は、v-onディレクティブでバインドするイベントの処理順序を変更しますので、v-onディレクティブでバインドするイベントに続けて記載します。
.capture修飾子の書式
.capture修飾子は、v-onディレクティブを使用したイベントのバインド時に以下のように記載します。
1 |
<要素 v-on:イベント名.capture> |
.capture修飾子の動作
.capture修飾子をイベントに対して指定した時の動作は、イベントターゲットの要素にaddEventListener()メソッドでイベントリスナーを登録する際にaddEventListener()メソッドの第3引数のuseCaptureにtrueを指定した時と同様の動作になります。
EventTarget.addEventListener() – MDN
動作を確認するためのサンプルコード
以下に.capture修飾子の動作を確認するためのサンプルコードを示します。
ここでは.capture修飾子を指定する場合と指定しない場合での違いを確認するために、.capture修飾子を指定しない場合のコードと指定する場合のコードで実行結果を比較します。
まずは.capture修飾子を指定しない場合の処理です。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="app"> <div id="myParent" v-on:click="onClickParent"> 親要素 <div id="myElement" v-on:click="onClickMe"> 自要素 <div id="myChild" v-on:click="onClickChild"> 子要素 </div> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Vue.createApp({ methods: { onClickParent: function(e) { console.log('親要素のclickイベントが発生'); }, onClickMe: function(e) { console.log('自要素のclickイベントが発生'); }, onClickChild: function(e) { console.log('子要素のclickイベントが発生'); }, } }).mount('#app') |
div要素が3階層で入れ子(ネスト)の状態で配置され、それぞれの要素のclickイベントにイベントハンドラーのメソッドがバインドしています。
上記のコードを実行すると、コンソールログには以下の結果が表示されます。
1 2 |
自要素のclickイベントが発生 親要素のclickイベントが発生 |
1 2 3 |
子要素のclickイベントが発生 自要素のclickイベントが発生 親要素のclickイベントが発生 |
1 |
親要素のclickイベントが発生 |
次に、v-onディレクティブのイベントバインドに.capture修飾子を指定します。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="app"> <div id="myParent" v-on:click.capture="onClickParent"> 親要素 <div id="myElement" v-on:click.capture="onClickMe"> 自要素 <div id="myChild" v-on:click.capture="onClickChild"> 子要素 </div> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Vue.createApp({ methods: { onClickParent: function(e) { console.log('親要素のclickイベントが発生'); }, onClickMe: function(e) { console.log('自要素のclickイベントが発生'); }, onClickChild: function(e) { console.log('子要素のclickイベントが発生'); }, } }).mount('#app') |
上記のコードを実行すると、コンソールログには以下の結果が表示されます。
1 2 |
親要素のclickイベントが発生 自要素のclickイベントが発生 |
1 2 3 |
親要素のclickイベントが発生 自要素のclickイベントが発生 子要素のclickイベントが発生 |
1 |
親要素のclickイベントが発生 |
.capture修飾子を指定すると、イベントが発生する順序が逆になりキャプチャフェーズでイベントが発生していることが確認できます。
.stop修飾子を合わせて指定した場合の動作の確認
.capture修飾子を指定する際に、合わせてイベントの伝播をキャンセルする.stop修飾子を指定した場合の実行結果も参考のために記載しておきます。
まずは、.capture修飾子を指定せずに.stop修飾子のみ指定した場合です。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="app"> <div id="myParent" v-on:click.stop="onClickParent"> 親要素 <div id="myElement" v-on:click.stop="onClickMe"> 自要素 <div id="myChild" v-on:click.stop="onClickChild"> 子要素 </div> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Vue.createApp({ methods: { onClickParent: function(e) { console.log('親要素のclickイベントが発生'); }, onClickMe: function(e) { console.log('自要素のclickイベントが発生'); }, onClickChild: function(e) { console.log('子要素のclickイベントが発生'); }, } }).mount('#app') |
上記のコードを実行すると、コンソールログには以下の結果が表示されます。
1 |
自要素のclickイベントが発生 |
1 |
子要素のclickイベントが発生 |
1 |
親要素のclickイベントが発生 |
.stop修飾子を指定すると、クリックした要素(イベントが発生した要素)でのみイベントハンドラーのメソッドが実行されているのが確認できます。
次に.capture修飾子と.stop修飾子を合わせて指定した場合です。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="app"> <div id="myParent" v-on:click.capture.stop="onClickParent"> 親要素 <div id="myElement" v-on:click.capture.stop="onClickMe"> 自要素 <div id="myChild" v-on:click.capture.stop="onClickChild"> 子要素 </div> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Vue.createApp({ methods: { onClickParent: function(e) { console.log('親要素のclickイベントが発生'); }, onClickMe: function(e) { console.log('自要素のclickイベントが発生'); }, onClickChild: function(e) { console.log('子要素のclickイベントが発生'); }, } }).mount('#app') |
コードの実行結果は以下のようになります。
1 |
親要素のclickイベントが発生 |
1 |
親要素のclickイベントが発生 |
1 |
親要素のclickイベントが発生 |
キャプチャフェーズでイベントが処理されるため、親要素(最上位の要素)でのみイベントが発生し、下位の要素ではイベントが発生しなくなります。