今回はVue.jsでのイベントハンドリングを紹介します。
Notice 
記事中のCodePenは右上の "Edit on CodePen" からコード編集画面に遷移できます。
ぜひ手元でコードを変えて結果を確かめてみてください。理解が早まると思います。
前提
| マシーン | ブラウザ | Vue |
|---|---|---|
| macOS Sierra 10.12 | Firefox Quantum | ver. 2.5 |
イベントとmethods
Vue.jsでのイベントハンドリングは普通にHTMLにJavaScriptを書くのとほとんど同じなので、わかりやすいかと思います。
イベントの登録には以下のように v-on 属性を用います。
<button v-on:click="something = true">Push</button>
v-on:イベント名="***" という形式で記述します。属性の値の部分はJavaScriptの式もしくはメソッド名です。
v-on: の部分は @ で置き換えることができます。v-on:click="***" であれば、@click="***" とも書けるわけです。@ は糖衣構文であって、2通りの書き方に機能的な違いは全くありません。私は @ の方が短く視認性にも優れると感じるので @ を使います。
@ 属性の値にはメソッド名も取れると書きましたが、単なる関数ではいけません。以下のように、Vueインスタンスの生成時にコンストラクタに渡す設定オブジェクトの methods プロパティに定義された関数でなくてはならないのです。
<button @click="someFunc">Push</button>
<script>
var app = new Vue({
el: '#app',
data: {
something: false
},
methods: {
someFunc: function () {
this.something = true
}
}
})
</script>
data プロパティに定義された変数でなければVueアプリ内で扱えないのと同様ですね。(上記の例において、someFunc 関数内で data プロパティに定義された something に、this を通してアクセスしていることにお気づきでしょうか。この点については後ほど説明します。)
設定オブジェクトのプロパティはVue.jsアプリケーションにおいて特別な意味を持ちます。el と data に続き methods プロパティも覚えておきましょう。
methods プロパティに定義された関数はイベントハンドラとしてしか使えない、というわけではありません。
<button @click="someFunc">Push</button>
<script>
var app = new Vue({
methods: {
someFunc: function () {
this.hello()
},
hello: function () {
console.log('hello')
}
}
})
</script>
このように、設定オブジェクト内では this を通してアクセスすることができます。
設定オブジェクトでの this は何者か?
設定オブジェクトで this を初めて登場させましたので、少し説明を加えます。
<button @click="someFunc">Push</button>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'Evan You'
},
methods: {
someFunc: function () {
this.hello()
},
hello: function () {
console.log('Hello, ' + this.name)
}
}
})
</script>
ご覧の通り、data に定義された変数や methods に定義された関数には、設定オブジェクト内では this を通してアクセスすることができます。
ここで this が指し示すものは、Vueインスタンスです。
this は設定オブジェクトそのものではありませんのでご注意ください。例えば this.methods などと書いて methods プロパティにアクセスすることはできません。
下の図は設定オブジェクト内で this をコンソール出力した結果です。
赤枠で囲った部分にご注目ください。data や methods に定義した変数・関数が、Vueインスタンスのプロパティに加えられていますね。だからこそ、this がVueインスタンスを指すときに、 this.hello() のようなアクセスが可能となるわけです。
さて、最後にいくつかイベントの利用例を見ていきましょう。
タブ - @click
簡単なタブのサンプルです。
clickイベントで currentTab の値を切り替えています。ここで注目していただきたいのは @click="toggle(1)" のように、イベントハンドラは引数を取れるということです。
あとはタブのコンテンツ側(文章が書いてある側)で v-show を用いて、currentTab の値にしたがって要素を見せたり隠したりしています。つまり、toggle 関数内で currentTab の値が変更されるとすぐに(自動的に)テンプレート側にもその変更が反映され、v-show が再評価されています。このようなUIとデータのシームレスな連携はVue.jsの真価と言えるでしょう。
フォーム - @submit
続いてフォームの例です。
この例で注目していただきたいのは、@submit.prevent="onSubmit" です。
Ajaxを用いてフォーム送信をする場合、Vue.jsを使わずに書くと以下のようにメインロジックの前に preventDefault メソッドを実行するかと思います。
function onSubmit (event) {
event.preventDefault()
// メインロジックがつづく...
}
preventDefault メソッドを実行しないと、Ajaxリクエストを送りたいメインコードなどお構いなしにHTML側でのフォーム送信が走って画面遷移が発生してしまうからですが、まぁこの辺はみなさんご存知かもしれません。
Vue.jsでは、@submit.prevent と書くと勝手に preventDefault() してくれます。
便利ですね。
ちなみに上で指摘したデフォルトのフォーム送信を避けるために、例えば <form> を書かず <button> の type 属性を "submit" ではなく "button" としてclickイベントでAjax通信を行っても動きとしては変わりませんが、そのような書き方はアクセシビリティ的にはNGらしいです。
どこがフォームでどこが送信ボタンなのかわからなくなってしまうからなのだそうです。
ファイルプレビュー - @change
こちらはフォームで選択した画像ファイルをその場でプレビュー表示する例です。
前回のフォーム入力についての記事でも言及しましたが、<input type="file"> の場合は v-model では選択したファイルそのものは取得できません。
そのため(Vue.jsを使わない場合と同様に)<input> のchangeイベントでeventオブジェクトを受け取ってそこからファイルを取得します。
<input type="file" @change="onFileChange" accept="image/*">
methods: {
onFileChange: function (event) {
このように、イベント登録側では特に何も書かなくても、ハンドラの引数としてeventオブジェクトを受け取ることができます。
ただしeventオブジェクトの他にも引数を渡したい場合にはeventオブジェクトも明示的に指定してやる必要があります。
<button type="button" @change="onClick(event, 123)">Push</button>
methods: {
onClick: function (event, number) {
以上、Vue.jsでのイベントハンドリングを紹介しました。
より詳しくはマニュアルを参照してください。
イベントハンドリング — Vue.js
関連記事
Vue.js入門(全7回)
- Vue.js入門 (1) el, data
- Vue.js入門 (2) テンプレート
- Vue.js入門 (3) クラスとスタイル
- Vue.js入門 (4) フォーム入力
- Vue.js入門 (5) イベントとmethods
- Vue.js入門 (6) 算出プロパティ
- Vue.js入門 (7) ウォッチャ

