LoginSignup
22
17

More than 3 years have passed since last update.

Vue.jsのイベントハンドラを勉強する

Last updated at Posted at 2019-07-16

イベントハンドラ

イベントの購読(サブスクライブ)

v-onディレクティブを使うことで、DOMイベントの購読、イベント発火時のjavascriptの実行

<div id="example">
  <p>ボタンを押すとカウントが増えます</p>
  <p>カウント: {{ counter }}</p>
  <button @click="counter += 1">カウントアップ!</button>
</div>
let app = new Vue({
  el: '#example',
  data: {
    counter: 0
  }
})

ブラウザ上ではボタンを押すたびにカウントが増えていきます。

メソッドイベントハンドラ

イベントハンドラのロジックは複雑になっていくので、v-on属性の値に式を記述し続けるのはアンチパターンです。
そのためv-onは呼び出したいメソッド名を記述する事ができます。

<div id="example">
  <p>ボタンを押すとカウントが増えます</p>
  <p>カウント: {{ counter }}</p>
  <button @click="countUp">カウントアップ!</button>
</div>
let app = new Vue({
  el: '#example',
  data: {
    counter: 0
  },
  methods: {
    countUp:function(){
      this.counter += 1
    }
  }
})

インラインメソッドハンドラ

メソッド名を直接指定する代わりに、インラインメソッドを指定することもできます。

<div id="example">
  <p>{{ message }}</p>
  <button @click="say('こんちわ')">こんにちは</button>
  <button @click="say('こんばんわ')">こんばんわ</button>
</div>
let app = new Vue({
  el: '#example',
  data: {
    message: '挨拶'
  },
  methods: {
    say:function(message){
      this.message = message
    }
  }
})

インラインステートメントハンドラでオリジナルのDOMイベントを参照する方法があります。

特別な $event変数を使うことでメソッドにDOMイベントを渡すことができます。

<div id="example">
  <p>{{ message }}</p>
  <button @click="say('こんちわ', $event)">こんにちは</button>
</div>
let app = new Vue({
  el: '#example',
  data: {
    message: '挨拶'
  },
  methods: {
    say:function(message, event){
      console.log(event)
      this.message = message
    }
  }
})

console.log()でボタンが押された時にDOMイベントを出力しています。

気になる人は実装してみてください。

イベント修飾子

イベントハンドラ内でのevent.preventDefault( )、またはevent.stopPropagation( )の呼び出しは、様々な場面で必要になります。
DMOの込み入った処理をおこなうよりも、単純なデータロジックだけになっていた方が扱いすいです。
Vue.jsはこの問題を解決するためにv-onのためにイベント修飾子(event modifiers)がサポートされています。

.stop

通常、同じイベントをハンドルしたDOMがネストされている場合、親要素に向かってイベントが連鎖する。
下記の例ではdiv(親要素)の中にbutton(子要素)があり、両方とも同じイベントをハンドルしています。
.stopを使用することでhandler(子要素)は実行されるが、handler(親要素)は実行されない。

<div id="example">
  <p>.stopなし</p>
  <div @click="handler('親要素')">
    <button @click="handler('子要素')">
      イベント実行ボタン
    </button>
  </div>

  <p>.stopあり</p>
  <div @click="handler('親要素')">
    <button @click.stop="handler('子要素')">
      イベント実行ボタン
    </button>
  </div>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'のイベント実行')
    }
  }
})

.prevent

Event.preventDefault()を呼ぶ。v
下記の例ではイベント(handler())は実行されるが画面遷移は行われない

<div id="example">
  <p>.preventなし</p>
  <a href="https://qiita.com/Sthudent_Camilo/items/58b8c21af0db5bea2340" @click="handler('Vue.js を勉強する Session1に遷移する')">
    Vue.js を勉強する Session1に遷移
  </a>

  <p>.preventあり</p>
  <a href="https://qiita.com/Sthudent_Camilo/items/58b8c21af0db5bea2340" @click.prevent="handler('Vue.js を勉強する Session1に遷移しない')">
    Vue.js を勉強する Session1に遷移しない
  </a>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element)
    }
  }
})

.capture

キャプチャーモードでDOMイベントをハンドルする。
ルート要素から順番にイベントが実行される。

<div id="example">
  <div @click.capture="handler('親要素')">
    <button @click="handler('子要素')">イベントを実行</button>
  </div>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

handler('親要素') -> handler('子要素')の順番で実行されます。

通常、イベントが発生すると、キャプチャーフェーズでルート要素から要素を探し、ターゲットフェーズで発生要素を検出、パブリングフェーズでルートまで要素をさかのぼりますが、キャプチャーモードにするとキャプチャーフェーズでイベントが発生します。

.self

実行した要素のみが処理を行われ、他の要素のイベントは実行されない。

<div id="example">
  <div @click.self="handler('親要素')">
    <button @click="handler('子要素1')">イベントを実行</button>
    <button @click="handler('子要素2')">イベントを実行</button>
  </div>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

.native

コンポーネントのルート要素上のネイティブイベントをハンドルする
※コンポーネントについて勉強不足なため今回はこんな感じだよ程度に記載

<!-- コンポーネントをクリックするとhandlerが呼び出される -->
<my-component @click.native="handler"></my-component>

<!-- コンポーネントをクリックしてもhandlerが呼び出されない -->
<my-component @click="handler"></my-component>

.once

1回だけイベントが実行される。

<div id="example">
  <button @click.once="handler('初回イベント実行')">イベントを実行</button>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

.passive

event.preventDefault()を呼び出さない事を明示する。
(.preventとの併用不可)

修飾子は繋げることができる

<div id="example">
  <div @click="handler('親要素')">
    <button @click.stop.once="handler('子要素')">
      イベント実行ボタン
    </button>
  </div>  
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

イベント修飾子は繋げて書くことができ、上記の例では子要素だけ実行されるイベントが1回だけ行われ、そのあとは親要素のイベントだけ呼ばれるようになります。

キー修飾子

キーボードイベントを検出するにあたって、特定のキーチェックが必要になった時にVue.jsではv-onに対してキー修飾子を追加することができます

  • .entser
  • .tab
  • .delete (windowsだとbackspace)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

上記のキー修飾子から .enter を利用して例を作ります。
下記の例ではbuttonは左クリックでは実行されず、Enterキーで実行されます。

<div id="example">
  <button @keyup.enter="handler('イベント実行')">
    Enterで実行ボタン
  </button>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

KeyboardEvent.keyで公開されているキャメルケースのキー名は、ケバブケースに変換することで修飾子として直接使用できます。

キーコード

【注意】
keyCodeイベントの使用は非推奨で、新しいブラウザではサポートされない可能性があります。
Vue.jsで使用することはできますが、今回は説明しません。

システム修飾子

下記の修飾子を使用すると、対応するキーが押された時にのみキーボードのイベントリスナを実行できます。

  • .ctrl
  • .alt
  • .shift
  • .meta

【注意】
Macintosh キーボードの場合、meta はコマンドキー(⌘)です
Windows のキーボードでは、meta はウィンドウキー(⊞)です
Sun Microsystems のキーボードでは、メタは実線のダイヤモンド(◆)とマークされています。
特定のキーボードでは、特に MIT や Lisp マシンのキーボードと Knight キーボード、space-cadet キーボード、メタのような後継機には “META” と表示されます。 Symbolics のキーボードでは、 “META” または “Meta” というラベルが付いています。

<div id="example">
  <button @keyup.enter.ctrl="handler('イベント実行')">
    Enterで実行ボタン
  </button>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

【注意】
修飾子キーは通常のキーとは異なり、keyup イベントで使用する場合、イベント発生時に押されていなければならない。
言い換えると、keyup.ctrl は ctrl を押しながら何かのキーを離したときにのみ、実行されます。
ctrl キーだけを離しても、トリガされません。
トリガされることを望むなら、ctrl ではなく keyup.17 のように keyCode を使用します。

.exact 修飾子

イベントを実行するために必要なシステム修飾子の正確な組み合わせを制御する。

<div id="example">
  <!-- これは Ctrl に加えて Alt や Shift キーが押されていても発行されます -->
  <button @click.ctrl="handler('イベント実行')">@click.ctrl</button>

  <!-- これは Ctrl キーが押され、他のキーが押されてないときだけ発行されます -->
  <button @click.ctrl.exact="handler('イベント実行')">@click.ctrl.exact</button>

  <!-- これは システム修飾子が押されてないときだけ発行されます -->
  <button @click.exact="handler('イベント実行')">@click.exact</button>
</div>
let app = new Vue({
  el: '#example',
  methods: {
    handler:function(element){
      alert(element + 'が実行されました')
    }
  }
})

マウスボタンの修飾子

イベント実行のハンドリングを特定のマウスのボタンのみに制限します。
使用方法は上記の修飾子と同様です。

なぜHTMLにイベントリスナを記述するのか

v-onを利用することでいくつかの利点があるからです。

  • HTML テンプレートを眺めることで、JS コード内のハンドラ関数を探すことを容易にします

  • JS内のイベントリスナーを手作業で加える必要がないので、ViewModelをDOM依存のない純粋な処理にできます。これはテスタビリティも向上します。

  • ViewModel が消去されるときに、すべてのイベントリスナーは自動で削除されます。手動でそれらの消去をおこなうことを気にする必要がない。

あとがき

今回の記事ではhtmlとjsのコードにタグを付けずに掲載することにしました。
Qiita独特の機能らしくmdをエディタでプレビューするときに上手く反映されず、変更を加えるのが手間だったためです。

参考資料

[メモ]Vue.jsイベント修飾子一覧

Vue.js公式リファレンス

22
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
17