Chapter 03

イベントハンドリング

OJK
OJK
2021.08.18に更新

今回は petite-vue でのイベントハンドリングを紹介します。ボタンを押すと数字が増えるといったように、イベント(ユーザのアクションやブラウザの状態)に反応して実行される処理です。

雛形コード
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>petite-vue入門</title>
</head>
<body>

  <button>押してください</button>

  <script src="https://unpkg.com/petite-vue"></script>
  <script src="script.js"></script>
</body>
</html>
script.js
'use strict';

PetiteVue.createApp({

}).mount();

JavaScript のイベントハンドリング

素の JavaScript で、特定の HTML 要素に対するイベント(クリックなど)に何らかの処理を割り当てるには次のように記述しました(忘れてしまった人はこちら)。

HTML
<button>押してください</button>
JS
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
  window.alert('押すな!');
});

addEventListener メソッドの第 2 引数は “コールバック関数” といって、対象となる HTML 要素がイベントを受け取ったときに呼び出される関数です。

addEventListenerメソッド
HTML要素.addEventListener('イベント名', コールバック関数);

前述のサンプルコードでは無名関数としてコールバック関数を登録していましたが、次のように別途定義した関数を登録することもできます。関数を「登録」する場合は末尾の () は付けないことに注意してください。

JS
const btn = document.querySelector('button');
btn.addEventListener('click', func); // 末尾の()は付けない

// コールバック関数
function func() {
  window.alert('押すな!');
}

イベントハンドリングのために紐付ける必要があるのは次の三者であることを頭に入れてください。

  • 対象とするイベント('click' など)
  • イベントを受け取る HTML 要素(button 要素など)
  • イベントを受け取ったときに実行されるコールバック関数

v-on ディレクティブ

petite-vue では、HTML 要素の特別な属性として用意された v-on ディレクティブ を使って、イベント・HTML 要素・コールバック関数の三者を関連付けます。

v-onディレクティブ
<HTML要素名 v-on:イベント名="コールバック関数名">
<HTML要素名 v-on:イベント名="コールバック関数()">

コールバック関数の名前だけを記述しても、末尾に () を付けて関数呼び出しの形にしても構いません。前者は addEventListener メソッドと同じく「関数の登録」を意味します。関数呼び出しの形でも成立するのは、口ひげ構文と同じく、v-on ディレクティブの " " 内には JavaScript の式が記述できるからです(関数呼び出しも式なので)。

コールバック関数は、createApp メソッドの引数内でメソッドとして定義します。

JS
PetiteVue.createApp({
  コールバック関数名() {
    /* 処理 */
  }
}).mount();
Vue を使う

本家 Vue の場合、コールバック関数にせよ、通常のメソッドにせよ、methods プロパティの下のオブジェクト内で定義します。算出プロパティ(computed)と同じ形式です。

JS
Vue.createApp({
  methods: {
    コールバック関数名() {
      /* 処理 */
    }
  }
}).mount('body');

さきほどのサンプルを petite-vue で書き換えてみましょう。

HTML
<button v-on:click="func">押してください</button>
JS
PetiteVue.createApp({
  func() {
    window.alert('押すな!');
  }
}).mount();

コールバック関数に引数を取ることもできます。その場合は関数呼び出しの形(末尾に () が付く)になります。

HTML
<button v-on:click="func('押すな')">押してください</button>
<!-- 関数呼び出しの形で記述する -->
JS
PetiteVue.createApp({
  func(msg) {  // 引数あり
    window.alert(msg);
  }
}).mount();

ところで @click="func('押すな')" の部分を見てみると、引用符が二重になっています。HTML の属性値はダブルクオート " " で囲うことになっていますから、その中でさらに " は使えません。本講座シリーズにおいて JavaScript でシングルクオート ' ' を使うようにしてきたのはこのためです。

なお、v-on は、ディレクティブの中でもよく使われるので省略形があります。「v-on:」の代わりに「@」と書くことができます。

v-onディレクティブ(省略形)
<HTML要素名 @イベント名="コールバック関数名">

さきほどの例は次のように書けます。

HTML
<button @click="func">押してください</button>

本講座でも今後は v-on: ではなく @ を使っていきます。

コールバック処理の直接記述

なお、v-on の " " 内に JavaScript の式が記述できるということは、コールバック関数の中身が単体の式の場合、わざわざメソッドで定義せずに中身を直接書くこともできるということです。

HTML
<button @click="window.alert('押すな!')">

本チャプターでは混乱を避けるためにコールバック処理は全てメソッドで定義しますが、次回以降はサンプルコード短縮のために直接記述も使っていきます。

Vue の関数

createApp メソッドの引数内では「コールバック関数しか定義できない」というわけではありません。口ひげ構文やその他のディレクティブの中で使える普通の関数(メソッド)も同じように定義できます。

HTML
<p>10 * 10 = {{square(10)}}</p>
<!-- 「10 * 10 = 100」と表示される -->
JS
PetiteVue.createApp({
  square(n) {
    return n * n;
  }
}).mount();

メソッドは、同じ createApp メソッドの引数内で定義されている他のメソッドやゲッターから呼び出されることもあります。その場合は同じオブジェクト内から呼び出すことになるので this が必要です。以下の例を読み解いてみてください。

HTML
<p>{{squared_x}}</p>
<!-- 「25」と表示される -->
JS
PetiteVue.createApp({
  // データプロパティ
  x: 5,

  // メソッド
  square(n) {
    return n * n;
  },

  // ゲッター
  get squared_x() {
    // データプロパティやメソッドを使うときはthisが必要
    return this.square(this.x);
  }
}).mount();

なお、コールバック関数の登録とは異なり、口ひげ構文の中で petite-vue のメソッドを使うときは必ず丸括弧 () 付きの「関数呼び出し」となります。前述のサンプルコードでは square が引数ありだったので自然と () 付きになっていますが、引数がなくとも末尾に () が必要です。

HTML
<p>Say {{say()}}</p>
<!-- 単なる関数呼び出しなので say とは書けない -->

<button @click="sayYes()">Say</button>
<button @click="sayYes">Say</button>
<!-- v-on は sayYes でも sayYes() でもよい -->
JS
PetiteVue.createApp({
  say() {
    return 'Yes';
  },
  sayYes() {
    window.confirm('Yes');
  },
}).mount();

$event 変数

form 要素の下に置かれた button 要素をクリックすると、form 要素の action 属性に指定されたファイルに画面がリダイレクト(転送)されます。action 属性が指定されていない場合は、画面が再読み込みされます。これは HTML の規定動作のひとつです。

下のコードは、ボタンを押すと文字を「No」から「Yes」に変更するものです。なお、データプロパティの値は this.プロパティ名 = 値/式 によってメソッド等から変更することができます。

HTML
<p>{{message}}</p>
<form>
  <button @click="func">押す</button>
</form>
JS
PetiteVue.createApp({
  message: 'No',
  func() {
    this.message = 'Yes';
  },
}).mount();

しかし実行してみると、一瞬「Yes」に変わったあと、すぐに「No」に戻ってしまいます。前述の form 要素の規定動作が働いて、画面が再読み込みされてしまうためです。

この規定動作を止めるために、素の JavaScript には preventDefault メソッド が用意されていたのでした。

JS
const btn = document.querySelector('button');
btn.addEventListener('click', (ev) => {
  ev.preventDefault();
});

無名関数の仮引数[1]として唐突に登場した変数 ev は Event オブジェクト と呼ばれ、preventDefault メソッドを呼び出したり、currentTarget プロパティを介してイベントを受け取った要素にアクセスしたりできます(変数名は ev でなくても構いません)。

petite-vue でも同様に、コールバック関数の定義に仮引数をひとつ記述することで Event オブジェクトを受け取ることができます。

JS
PetiteVue.createApp({
  message: 'No',
  func(ev) {
    this.message = 'Yes';
    ev.preventDefault();  // 規定動作を止める
  },
}).mount();

コールバック関数に独自の引数を渡したい場合には、HTML 側で明示的に $event を実引数に指定することで Event オブジェクトを受け取ることができます。

HTML
<p>{{message}}</p>
<form>
  <button @click="func('Yes', $event)">押す</button>
</form>
JS
PetiteVue.createApp({
  message: 'No',
  func(msg, ev) {  // msg←'Yes', ev←$event
    this.message = msg;
    ev.preventDefault();
  },
}).mount();

v-on ディレクティブにコールバック関数を「登録する」か「呼び出すか」で Event オブジェクトの受け取り方が異なりますが、複数のパターンを覚えるのが面倒なら、独自の引数がないときでも <button @click="func($event)">押す</button> として常に $event を実引数に指定しておけば統一的に扱えます。

Event オブジェクトを介してできることは こちら を参照してください。

修飾子

v-on でも Event オブジェクトを受け取れることはわかったのですが、preventDefault するだけなら実はもっと簡単な方法が用意されています。v-on ディレクティブには 修飾子/Modifiers と呼ばれるオプションがあり、例えば、preventDefault メソッドと同じ効果を次のようにして付与することができます。

HTML
<p>{{message}}</p>
<form>
  <button @click.prevent="func">押す</button>
</form>

v-on ディレクティブに指定するイベント名の後ろに「.prevent」と付ければ、コールバック関数の定義の中で preventDefault メソッドを呼ぶ必要はなくなります。

画面を再読み込みする規定動作は form 要素の submit イベントなので、<form @submit.prevent> とするのがより正しい記法です。ただ、button 要素の click イベントに .prevent を付けても規定動作を止めてくれます。

他にもいくつか修飾子はあります。修飾子の詳細については Vue のドキュメント を参照してください。特に、受け付けるキーを修飾子で選択できるのは便利です。

脚注
  1. 関数定義の引数を「仮引数(parameter)」、関数呼び出しの引数を「実引数(argument)」と呼ぶのでした。 ↩︎