見出し画像

作りながら学ぶVue.js パート4【入力フォームの作成】

このnoteは、JavaScriptのフレームワークであるVue.jsを初心者でも扱えるようになることを目指して、実際にアプリケーションを作りながら学んでいくチュートリアルです。

前のパートから実際にアプリケーションを作り始め、一番単純なヘッダーの表示までを行いました。

今回はタスク管理ツールのキモである入力フォーム部分の作成を通じてVue.jsにおける重要な機能を紹介していきます。

フォーム部分のコンポーネント作成

前回説明したヘッダーと同様に新しくフォームを表示するためのコンポーネントを作ることから始めていきます。

今回もsrc/components配下に新規でForm.vueという名前でファイルを作成します。

ファイルを作成したら、早速コーディングしていきます。前回のヘッダーよりも複雑なコンポーネントとなりますので、段階的に説明していきます。

まずはHTMLとしての役目を担うtemplateタグの中身。まずはほぼそのままフォームを構成するHTML要素を並べることから始めます。

<template>
  <div class="container">
    <div class="item">
      <input type="text" name="title">
    </div>
    <div class="item">
      <input type="text" name="period">
    </div>
    <div class="item">
      <textarea name="detail"></textarea>
    </div>
    <div class="item">
        <button>作成</button>
    </div>
  </div>
</template>

よくあるフォーム画面のHTMLコードですね。

タスクのタイトル・期限・詳細を入力することができるフォーム画面の枠組みとなります。

この時点だと当然ボタンを押しても何も起こりませんし、Vue.jsで動かすためには不足している記述があるのですが、そちらはJavaScript部分を作成してから追記していきます。

次にJavaScript部分の開発に移っていきます。

今回のJavaScript部分においてやるべきことは以下の2つ

・フォームに入力されたデータを入れておく場所を作る
・「作成」ボタンが押された時の処理を実装する

細かい処理を省略すると以下のような実装になります。

<script>
export default {
  data() {
    return {
      inputTitle: "",
      inputPeriod: "",
      inputDetail: ""
    };
  },
  methods: {
      createTask() {
          // タスクを作成する処理
      }
  }
};
</script>

「フォームに入力されたデータを入れておく場所を作る」を実現しているのが、data(){}で返されている3つの要素

「作成ボタンが押された時の処理を実装する」がmethodsの中のcreateTask()で実現される形になります。

dataについて

dataについては単語から想像しやすいかもしれませんが、コンポーネントにおいて動的に変化するデータの格納場所として機能します。

sampleというデータが用意されている場合、

・templateタグの中からは{{ sample }}という形
・scriptタグの中からはthis.sampleという形

でアクセスすることができます。

<template>
  <div id="app">{{ sample }}</div>
</template>

<script>
export default {
  name: "app",
  data() {
    return {
      sample: "これはサンプルだ"
    };
  },
  methods: {
    demo() {
      console.log(this.sample);
    }
  }
};
</script>

ちょっと難しい話になりますが、このdataというのはただの変数という訳ではありません。dataの値が画面表示に使われていた場合、dataが変更された際に画面表示も変わるリアクティブと形容される特性を持っています。

まだ説明できていない要素も使っているので、簡単にみておくだけで結構なのですが、以下のサンプルは「増やすよ」のボタンを押すと、increment()が呼び出され、その中でdataにあるcountが1加算されるようなコンポーネントです。

<template>
  <div id="app">
    <div>{{ count }}</div>
    <button v-on:click="increment">増やすよ</button>
  </div>
</template>

<script>
export default {
  name: "app",
  data() {
    return {
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    }
  }
};
</script>

dataがただの変数であれば、値が更新されても何も起こりませんが、Vue.jsの実装により、リアクティブなプロパティとなっているので、自分で値の変更を制御することなく画面表示の内容も変更されるようになっています。(画面の表示が変わることを再レンダリングなんて呼んだりもします)

もちろんここで説明している全てを理解する必要はありませんが、dataには画面開発に便利な機能があるんだな、程度に覚えておいてください。

methodsについて

methodsも名前から想像できる人が多いかと思いますが、そのコンポーネントにおける処理を格納するプロパティです。

・サーバーにリクエストを送る
・要素がクリックされた際に見た目を変える

などといったユーザーの操作に基づく更新処理などをメインに行うところといった認識でOKです。

JavaScriptに触れたことのある人であれば比較的イメージが湧きやすいのではないかと思います。

dataの補足

鋭い人は気になったかも知れませんが、export default{}の中において、dataとmethodsの書き方が違うことが気になったかと思います。

これはdataがデータの入れ物として機能している都合によって発生している差異であり、具体的には1つのコンポーネントを複数の場所で使った場合に生じかねない不具合を回避するための書き方となっています。

ちょっと難しいですね。

そういうものなんだ、と決まりごととして覚えておいても困る場面は少ないかも知れませんが、なんとなくイメージを掴んでおくといいかと思います。

公式サイトにも記載されているので、気になった方はご覧になってみてください。

templateタグとscriptタグの中身の連携

さてtemplateとscriptの中身、つまりHTMLとJavaScriptの部分の実装のベースを作ったところで、それぞれを組み合わせる手順に進みます。

まずはtemplateタグの中身を以下のように変更します。

<template>
  <div class="container">
    <div class="item">
      <input type="text" name="title" v-model="inputTitle">
    </div>
    <div class="item">
      <input type="text" name="period" v-model="inputPeriod">
    </div>
    <div class="item">
      <textarea name="detail" v-model="inputDetail"></textarea>
    </div>
    <div class="item">
        <button v-on:click="createTask">作成</button>
    </div>
  </div>
</template>

全部で4箇所、2パターンの記述が追加されています。

・input要素にv-modelという属性が追加されている
・button要素にv-on:clickという属性が追加されている

それぞれについて解説していきましょう。

v-modelについて

このv-modelを追加して、その値としてdataで定義したプロパティを設定することによって、scriptタグの中で定義したdataとinputに入力された値がシンクロするようになります。

要するにこれだけの記述で、

・inputのvalueが変更された場合、dataの値も同様に変更される
・dataの値が変更された場合、inputのvalueも変更される

といった状態を実現することができるわけです。

これをjQueryや素のJavaScriptで実現しようとした場合、

・inputの値変更をイベントで検知して、そのタイミングでHTML要素にアクセスしてデータを取得して変数に格納…
・変数の値を更新したらHTML要素にアクセスして値を変更…

といったような手間が必要になることを考えると非常に便利な機能ですね。

難しい言葉ですが「双方向バインディング」と表現される機能です。

ここで説明したような特性さえ把握しておけば、基本的な実装においては支障ありませんが、より詳しく知りたい人は公式ページのv-modelの項目をご覧になってみてください。

v-on:clickについて

次にbutton要素に追加されているv-on:clickについて説明します。

なんとなく想像がついている人もいるかも知れませんが、このv-on:clickはHTMLにおけるonclick属性と同じ感覚で利用できるものです。

このv-on:clickの値にmethodsで用意しておいたcreateTaskメソッドの名前をセットしておくことで、クリックした時にcreateTaskが実行されるということです。比較的イメージしやすいのではないかと思います。

この機能はイベントハンドリングと呼ばれ、v-on:clickだけではなく、inputにフォーカスされた時のv-on:focusやキーを押して話された時のv-on:keyupなどといったイベントも制御することが可能となっています。

dataの解説で使ったカウンターのサンプルにおいても、シレッと使われていますね。

ちなみにそのサンプルは以下のように直接処理を記載するという書き方でも実装が可能だったりします。

<template>
  <div id="app">
    <div>{{ count }}</div>
    <button v-on:click="count++">増やすよ</button>
  </div>
</template>

しかし基本的にはmethods内にメソッドを作り、そのメソッドを呼び出す、という元の書き方の方が見た目もわかりやすく、保守性にも優れているので、基本的に直接処理を書くやり方はあまりしない方がいいでしょう。

またv-on:xxxという書き方は@xxxという形で省略して記載することが可能です。つまりフォームのbutton部分は以下のようにも書き換えることが可能ということです。

<button @click="createTask">作成</button>

慣れてきたらこちらの省略記法を使うようにするといいでしょう。この連載においてはパッとみてわかりやすいように基本的には省略せずに記載していくつもりです。

ここまでの解説でなんとなく以下のコードの意図が掴めるようになったのではないかと思います。

<template>
  <div class="container">
    <div class="item">
      <input type="text" name="title" v-model="inputTitle">
    </div>
    <div class="item">
      <input type="text" name="period" v-model="inputPeriod">
    </div>
    <div class="item">
      <textarea name="detail" v-model="inputDetail"></textarea>
    </div>
    <div class="item">
        <button v-on:click="createTask">作成</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputTitle: "",
      inputPeriod: "",
      inputDetail: ""
    };
  },
  methods: {
      createTask() {
          // タスクを作成する処理
      }
  }
};
</script>

v-modelとdataの解説で少しボリューミーになってしまったので、コメントで省略している「タスクを作成する処理」の部分については次回解説させていただきます。

まとめ&課題

今回の記事でVue.jsにおいて重要な要素についてある程度理解が進んだかと思います。

結構覚えることが多かったと思うので、頑張りたい派の方は以下の課題にチャレンジしてみてください。回答は次回の冒頭で解説する予定です。

inputに値を入力して追加ボタンを押すと値がフォームの上に表示される画面

存在意義の薄い画面で恐縮ですが、今回学んだ内容の復習としてよかったらトライしてみてください。

次回はこちら


この記事が気に入ったらサポートをしてみませんか?