第8回 Vue.js入門 v-onディレクティブとmethodsプロパティ

Vue.jsのv-onディレクティブの使い方 プログラミング

こんにちは、コンスキです。

タイトルにもあるように、今回はv-onティレクディブとmethodsプロパティの2つについて解説していきます。

ディレクティブは5つ目で、Vueインスタンスのプロパティは4つ目になります。数が増えるごとにディレクティブとプロパティとの相互関係が重要になって来ます。

v-onディレクティブとmethodsプロパティも強いつながりを持ったもの同士です。

また、v-onディレクティブとこれまでに説明したv-bindディレクティブを組み合わせると、擬似的に双方向のバインディングを行うことができるようになります。

v-onディレクティブとは

v-onディレクティブとは、DOMのイベントを感知して、データの変更を行うディレクティブのことです。DOMのとは、例えばボタンのクリックやフォームの入力などのことです。

Vue.jsを使わないJavascriptだけでも、要素がクリックされたときに値の変更や関数の実行を行う動作であれば次のようなコードで実現することができます。

document.getElementById("要素のid").onclick = function() {
  // ここに要素をクリックした際に行う値の変更や関数の実行といった処理を書く
};

少ない個数の要素へのクリックに対する処理であれば、このコードを使った実現方法でも良いと思います。逆にVue.jsを使わないほうが全体のコード量としては少なくなることもあります。

しかし、たくさんの要素に対してクリックされたときの処理を実装することになった場合を考えます。すると、Vue.jsのv-onディレクティブを使ったほうがコードの量を考えるとより少ないコード量で書けることが多くなります。

また、コード量の少なさだけでなく、クリックされた際の処理を書くことだけに集中することができるという点もv-onディレクティブを使った場合に考えられるメリットです。

v-onディレクティブの使い方

先程、「たくさんの要素へのクリックに対する処理であれば、v-onディレクティブのほうが少ないコード量で書ける」と言いましたが、そう言えるようなv-onディレクティブの記述方法はどのようなものなのでしょうか。

基本的な書き方

それでは、v-onディレクティブの基本的な記述方法について説明します。v-onディレクティブの書き方は次のようになります。

<div id="app">
    <要素名 v-on:イベントの種類="イベントが起こったときに実行する式"></要素名>
</div>

イベントの種類は、クリックであれば「click」、フォームの入力であれば「input」になります。ここからの説明では、これら2つのイベントを使って説明します。

v-on:click

まず、clickイベントを使った例を挙げてみます。ボタンがクリックされたときに、Vueインスタンスのdataプロパティに設定されている値を変化させるコードは次のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-onディレクティブ</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>   
    <div id="app">
        <button v-on:click="counter++">クリックしてね</button>
        <p>ボタンがクリックされた回数:{{ counter }}回</p>    
    </div>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                counter: 0
            }
        })
    </script>
</html>
<div id="app">

p要素としてdataプロパティにある「counter」使っているため、ボタンを押すたびに画上の数字も変化します。ちなみにしたのスクリーンショットをときには、実際にボタンを3回クリックしました。

ブラウザ上の表示↓

v-on:input

次は、v-onディレクティブにinputイベントを使ったコードについて説明します。inputイベントはフォームの値が変更されるたびに起こります。

clickイベントであればクリックしたときに起こるイベントだということがわかりやすいですが、inputイベントはいつイベントが起きているのかが分かりづらいですよね。

繰り返しになりますが、inputイベントが起こるのはフォームに書いてある値が変化したときです。例えば、空白のフォームに「k」と入力したらイベントが起こります。そして、その「k」を BackSpace 押して空白の状態に戻したときにもインベントが起こります。

inputイベントを使ったv-onディレクティブのコードは次のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-onディレクティブ</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>   
    <div id="app">
        <input type="text" v-on:input="counter++">
        <p>フォームの内容が変化した回数:{{ counter }}回</p>    
    </div>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                counter: 0
            }
        })
    </script>
    </div>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                counter: 0
            }
        })
    </script>
</body>
</html>
<div id="app">

実行画面↓

注意しなければならない点は、フォームに日本語で入力したときのイベントが起こるタイミングです。「k」のような英語(アルファベット)であれば、一文字打つたびに毎回イベントが発生します。

一方で、日本語(ひらがなやカタカナ)を入力したときには、イベント発生のタイミングが文字の入力や削除だけだとは限りません。日本語を入力する際はSpaceキー押して変換をした時や Enter などを押して入力の確定をしたときにもイベントが起こります。

これらのタイミング共通している点は見た目に何かしらの変化がある点です。文字を入力したり削除したりするとフォームの中にある文字数が増減していることが目に見えてわかります。

文字の変換であっても違う何度も違う漢字に変わって見た目も変わっているのがわかると思います。分かりづらいですが、入力の確定時にも文字の下にある線がなくなるという見た目の変化があります。

inputイベントがいつ起こるのかを忘れてしまったら、フォームの内容が変化する時だと思い出しましょう。(全角スペースは1回押すだけで2回イベントが起こるという例外もあります)

4文字がしか入力していないの10回になっている↓

Methodsプロパティとは

Methodsプロパティとは、関数を書いておくためのプロパティです。プログラム中に使う関数をMethodsプログラムに書いておいて管理することができます。

今回説明したv-onディレクティブと一緒に使えば、「クリックされたときに関数を実行する」「フォームの変化ががったら関数を実行する」というようなこともできるようになります。

methodsプロパティの書き方

基本的な書き方

methodsプロパティは次のような書き方をします。

const vm = new Vue({
    el: "app",
    methods: {
        キー: function () {
            //ここに処理を書きます
        }
    }
})

mesthodsプロパティは、dataプロパティとは違って、値ではなく関数をプロパティに書きます。キーには関数を呼び出すときに使う名前だと考えて下さい。

「v-on:イベント発生時の処理」の処理をmethodsプロパティに移す

ここまでではv-onディレクティブのイベント発生時の処理を、下のように赤くなっている部分に書いていました。

<div id="app">
    <要素名 v-on:イベントの種類="イベントが起こったときに実行する処理"></要素名>
</div>

しかし、赤くなっている部分を処理を一つしか書くことができません。ブロック文は複数の文からなるためここに書くことができません。例えば、後置増分演算子を複数の値に対して使う処理をすることがないという事になります。

そこで処理はmethodsプロパティに移して、ここにはプロパティに設定した関数のキーを書くことで、複数の処理を実行することができるようになります。

HTML側↓

<div id="app">
    <要素名 v-on:イベントの種類="イベントが起こったときに実行する関数のキー(引数)"></要素名>
</div>

Javascript側↓

const vm = new Vue({
    el: "app",
    methods: {
        キー: function (引数) {
            //ここに処理を書きます
        }
    }
})

赤くなっている部分は同じものが入ることを意味しています。引数はあってもなくても大丈夫です。実行する関数に引数がない場合「(引数)」の部分を省略してキーのみを書くことができます。

「(引数)」の部分を省略した場合、自動的に引数にイベントオブジェクトというものが渡されます。イベントオブジェクトとは、イベントに関する情報が含まれるオブジェクトのことです。

例えば、イベントのイベントオブジェクトには入力された文字が含まれ、実行する関数の中で入力された文字を使った処理を行うことができます。

双方向バインディングのやり方

v-onディレクティブとv-bindディレクティブを一緒に使うことで、擬似的に双方向バインディングを行うことができます。

双方向バインディングを使うと、入力フォームに入力した文字を画面上の別の場所に表示させることもできます。

双方向バインディングの書き方の例は次のようになります。

HTML側↓

<div id="app">

    <p>{{ message }}</p>
    <input v-bind:value="message" v-on:input="changeMessage">    
</div>

Javascript側↓

const vm = new Vue({
    el: "#app",
    data: {
        message: ""
    },
    methods: {
        changeMessage: function(event) {
            this.message = event.target.value;
        }
    }
})

ブラウザ上の表示は次のようになります。

文字を打ち込むのと同時に打ち込んだ文字が画面上の別の部分にも表示されます。これが双方向バインディングです。

サンプルプログラム

ボタンのクリックやフォームの入力というのは、アプリケーションの中に必須と言ってもいいような要素です。今回説明したv-onディレクティブとmethodsプロパティを使ってサンプルプログラムを作ってみます。

プログラムの内容としては、前回の身長と体重からBMIを計算するプログラムとほとんど同じです。前回のプログラムはあらかじめ人が3人にが決まっていましたが、今回は名前と身長と体重を新しく設定してBMIを計算することができるようになっています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>v-forディレクティブ</title>
  <script src="https://unpkg.com/vue"></script>
</head>

<body>
  <div id="app">
    <div>
      <input v-on:input="setName" v-on:keydown.enter.exact="createPerson()" v-bind:value="newPerson.name"
        placeholder="名前を入力して下さい">
      <input v-on:input="setHeight" v-on:keydown.enter.exact="createPerson()" v-bind:value="newPerson.height"
        placeholder="身長を入力して下さい">
      <input v-on:input="setWeight" v-on:keydown.enter.exact="createPerson()" v-bind:value="newPerson.weight"
        placeholder="体重入力して下さい">
      <button v-on:click="createPerson()">計算する</button>
      <p v-if="nameAlert" v-bind:style="alertObjects[0]">名前を入力して下さい。</p>
      <p v-if="heightAlert" v-bind:style="alertObjects[1]">身長を入力して下さい。</p>
      <p v-if="weightAlert" v-bind:style="alertObjects[2]">体重を入力して下さい。</p>
    </div>
    <!-- 他の配列の要素の指定を行うためにindex配列peopleのインデックスを使う -->
    <div v-for="(person, index) in people" v-bind:key="person.name">
      <p>名前:{{ person.name }}</p>
      <p>身長:{{ person.height }}cm</p>
      <p>体重:{{ person.weight }}kg</p>
      <p v-bind:style="styleOject[index]">BMI:{{calcBMI[index]}}</p>
      <p v-show="isBitBig[index]">肥満気味です</p>
      <br>
    </div>
  </div>
  <script>
    const vm = new Vue({
      el: "#app",
      data: {
        people: [],
        //BMIが25以上の時に適用させるstyleオブジェクト
        alertObject: {
          color: '#FF7070',
          fontWeight: 'bold',
          border: '4px double #FF7070',
          display: 'inline'
        }
        ,
        alertObjects: [{}, {}, {}],
        newPerson: {
          name: undefined,
          height: undefined,
          weight: undefined
        },
        nameValue: undefined,
        heightValue: undefined,
        weightValue: undefined,
        nameAlert: false,
        heightAlert: false,
        weightAlert: false
      },
      computed: {
        calcBMI: function () {
          var BMI = [];
          for (var i = 0; i < this.people.length; i++) {
            var mHeight = this.people[i].height / 100;
            BMI.push(Math.floor(this.people[i].weight / mHeight / mHeight));
          }
          return BMI
        },
        isBitBig: function () {
          var flag = [];
          for (var i = 0; i < this.people.length; i++) {
            if (this.calcBMI[i] >= 25) {
              flag.push(true);
            } else {
              flag.push(false);
            }
          }
          return flag
        },
        styleOject: function () {
          var styleOjects = [];    //全員のsyleオブジェクトを入れておくリスト
          for (var i = 0; i < this.people.length; i++) {
            //BMIが25以上だったらdataプロパティにあるstyleオブジェクト返し、25未満だったら空のオブジェクトを返す
            var so = this.isBitBig[i] ? this.alertObject : {};
            styleOjects.push(so);
          }
          return styleOjects
        }
      },
      methods: {
        setName: function (event) {
          this.nameValue = event.target.value;
          this.newPerson.name = this.nameValue;
        },
        setHeight: function (event) {
          this.heightValue = event.target.value;
          this.newPerson.height = this.heightValue;
        },
        setWeight: function (event) {
          this.weightValue = event.target.value;
          this.newPerson.weight = this.weightValue;
        },
        createPerson: function () {
          // 空欄があればアラートを表示するフラグ、スタイルを設定
          this.nameAlert = !this.nameValue ? true : false;
          this.alertObjects[0] = !this.nameValue ? this.alertObject : {};
          this.heightAlert = !this.heightValue ? true : false;
          this.alertObjects[1] = !this.heightValue ? this.alertObject : {};
          this.weightAlert = !this.weightValue ? true : false;
          this.alertObjects[2] = !this.weightValue ? this.alertObject : {};
          if (this.nameValue && this.heightValue && this.weightValue) {
            this.people.push(this.newPerson);
            this.newPerson = {
              name: undefined,
              height: undefined,
              weight: undefined
            }
            this.nameValue = undefined;
            this.heightValue = undefined;
            this.weightValue = undefined;
          }
        }
      }
    })
  </script>
</body>
</html>

きれいなコードでなくて申し訳ありません。ブラウザ上に表示すると以下のようになります。

名前、身長、体重をフォームに入力して「計算する」と書いてあるボタンを押すことで、計算されたBMIが含まれた一覧が表示されます。

前回のサンプルプログラムと同様に、BMIが25以上であれば、「肥満気味です」のメッセージが表示されます。

また、名前、身長、体重のうち一つでも空欄がある状態でボタンを押すと警告が表示されます。

以上で今回の説明を終わりにします。読んでくれてありがとうございました。次回は今回説明した双方向バインディングをもっとかんたんに記述することができる、v-modelディレクティブについて解説します。

まとめ

今回わかったこと

  • ・v-onディレクティブはDOMのイベントを感知して処理や関数を実行できるディレクティブ
  • ・methodsプロパティはプログラム内の関数を一括して管理できるプロパティ
  • ・v-onディレクティブとv-modelディレクティブを使うと双方向バインディングを実現できる

コメント

タイトルとURLをコピーしました