LoginSignup
5
3

More than 5 years have passed since last update.

やさしめ Vue.js チュートリアル(2) ~ データとイベントの制御

Last updated at Posted at 2019-04-27

はじめに

こちらは やさしめ Vue.js チュートリアル(1) ~ Vue CLI でプロジェクト作成と Linter の設定 の続きとなります。

今回はデータとイベントの制御について学びます :muscle:

ハンズオン

1. 余計な記述の削除とタイトルの追加

まずは今回のハンズオン向けに初期状態の余計な記述を削除しましょう。

  • HelloWorld.vue を削除
  • App.vue 修正
    • タイトルを追加
    • HelloWorld コンポーネントを利用している箇所を削除
    • スタイルタグの中身を削除

以下のようになります。

App.vue
<template>
  <div id="app">
    <h1>Lovely Vue</h1>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

<style></style>

:zap: 動作 :zap:
真っ白な背景にタイトルだけが表示されていれば OK です :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/b656c9366307fed7a17db2721265ff0e463a22f4

2. 宣言的レンダリング

スクリプト側で定義したデータをtemplate側で表示する方法を学びます。

まず、スクリプト側で data として message を定義

App.vue
  export default {
-   name: "App"
+   name: "App",
+   data: () => ({
+     message: "Spark joy!"
+   })
  };

テンプレート側で {{ message }} と記述して表示させます。

App.vue
  <div id="app">
    <h1>Lovely Vue</h1>
+   {{ message }}
  </div>

:zap: 動作 :zap:
「Lovely Vue」の下に「Spark joy!」と表示されていれば OK です :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/275e6229a2aa10400389679d39f7b8929bc7d129

:bulb: ポイント :bulb:

  • data で変数を宣言
    • ここでは詳しく説明しませんが、data は関数でなければなりません1
  • {{ }} で囲めば変数を展開できる

3. ユーザー入力の制御

ユーザーの入力に応じて表示内容を変更してみましょう。

イベントリスナー登録(v-on)

テンプレート側にイベントリスナーを登録しましょう。
input 要素の input イベントが走ったときに onInput という名前の関数を呼ぶようにしておきます。

App.vue
  <div id="app">
    <h1>Lovely Vue</h1>
+   <input @input="onInput" />
+   <br />
    {{ message }}
  </div>

このままでは onInput という関数を呼ぼうとして存在せずエラーとなってしまうので、
スクリプト側に呼ばれるメソッドである onInput を定義しましょう。

この中で、入力内容を取得し message を上書きします。

App.vue
  export default {
    name: "App",
    data: () => ({
      message: "Spark joy!"
-   })
+   }),
+   methods: {
+     onInput(event) {
+       const text = event.target.value;
+       this.message = text;
+     }
+   }
};

:zap: 動作 :zap:
入力欄に入力した内容がその下に表示されるようになっていれば OK です :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/802a6b6d02d1d2f4f9dede8711715314e5af7eec

:bulb: ポイント :bulb:

  • @input でインプットイベントと関数を紐付け2
    • @input@ は生の JavaScript でいう addEventListener と考えておけば OK
  • methods で関数を宣言
  • スクリプト内では this のプロパティとして data にアクセスできる

双方向バインディング(v-model)

画面表示時は入力欄の中は空なのに、
入力欄の下には「Spark joy!」が表示されていますね。

なぜこれが起きているのか?というと、
入力内容 => message という方向には連動していますが、
message => 入力内容 という方向には連動していないからです。

これを連動させるため、双方向バインディング(v-model)を用います。3

テンプレート部分の input の記述を以下のように変更しましょう。

App.vue
- <input @input="onInput" />
+ <input v-model="message" />

いらなくなっちゃったので、スクリプト部分の onInput は削除しましょう。

App.vue
  export default {
    name: "App",
    data: () => ({
      message: "Spark joy!"
-   }),
+   })
-   methods: {
-     spark(event) {
-       const text = event.target.value;
-       this.message = text;
-     }
-   }
};

:zap: 動作 :zap:
表示時に入力欄に「Spark joy!」が入っていて、且つ、
入力内容に連動してその下の文字列が変化するはずです :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/c312b2c7413630980ef588c0e8bf5722c977759f

:bulb: ポイント :bulb:

  • v-model で入力内容と変数を双方向バインディングできる

4. ループ( v-for )

いわゆる for 文です。
v-for を使うことでループでDOMを追加できます。

まず、スクリプト部分で datatodos という変数を定義します。

App.vue
  data: () => ({
+   todos: [
+     { id: 1, text: "ときめき" }
+   ],
    message: "Spark joy!"
  })

テンプレート部分で v-for を使ってループで表示させます。

App.vue
  <input v-model="message" />
  <br />
+ <ul>
+   <li v-for="todo in todos" :key="todo.id" class="task-card">
+     {{ todo.text }}
+   </li>
+ </ul>

class は普通に HTML 属性としての class になります。
スタイル部分にそれっぽいスタイルも追加しておきましょう。

vue
- <style></style>
+ <style>
+ .task-card {
+ border: solid 1px;
+ margin: 5px;
+ padding: 2px;
+ width: 250px;
+ }
+ </style>

:zap: 動作 :zap:
「ときめき」と書かれたカードっぽいやつが表示されているかと思います :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/19757cc150d98c5b86513c8dc16bad6f1517843e

さらに、タスクを追加できるようにしましょう。
テンプレート側に追加ボタンを記述します。

App.vue
  <input v-model="message" />
+ <button @click="add">追加</button>
  <br />

スクリプト側に add という関数を定義し、この中で新しいタスクを追加します。

App.vue
-   })
+   }),
+   methods: {
+     add() {
+       const newTodo = {
+         id: this.todos.length + 1,
+         text: this.message
+       };
+       this.todos.push(newTodo);
+       this.message = "";
+     }
+   }
  };

:zap: 動作 :zap:
「追加」ボタンを押すとタスクが追加さるようになっていれば OK です :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/838eaf5f88deee4b886c26618793c83c020cd2a4

:bulb: ポイント :bulb:

  • v-for でテンプレート内で for 文が回せる

5. 算出プロパティ( computed )

気付いちゃった人もいるかもしれませんが、
このままでは入力欄が空でもタスクの追加ができちゃいます。

ダサいので、入力欄が空の場合は追加ボタンを無効化しましょう。

スクリプト部分に computed とその中に isDisabled という関数を定義します。

App.vue
    message: "Spark joy!"
  }),
+ computed: {
+   isDisabled() {
+     return this.message.length === 0;
+   }
+ },
  methods: {

message が空なら true を返します。
これをテンプレート部分で使います。

App.vue
- <button @click="add">追加</button>
+ <button :disabled="isDisabled" @click="add">追加</button>

これで、
入力内容が空の時は isDisabledtrue => disabled が有効化、
入力内容がある時は isDisabledfalse => disabled が無効化
します。

:zap: 動作 :zap:
入力欄が空の時に「追加」ボタンが押せなくなっていれば OK です :ok_hand:

:book: ソースコード :book:
https://github.com/taiju59/lovely-vue/commit/3778dd29f1d34284eb68861ae973edcbf58c9d28

:bulb: ポイント :bulb:

  • computed で算出プロパティを宣言
    • 定数や、既存の各変数から自動的に導き出される値を取得するために使います
    • 導出元の変数が変化すれば computed の結果も変わり、これに応じて DOM も変化します
  • HTML 属性に値を指定する際、 :disabled など : を前に付けると右辺はスクリプトとして変数が展開されます4

おわりに

Vue の基本についてかいつまんで学びました。
ここまでやれば、小さいものなら何か作れるちゃうかも?と
思ってもらえたかもしれません。

また、リアクティブなフレームワークが初めての人は、
双方向バインディングや算出プロパティで リアクティブの風 を感じてもらえたら嬉しいです。

次回はコンポーネントをファイル分割する方法について学びます。

次回 :point_right: やさしめ Vue.js チュートリアル(3) ~ コンポーネントによる構成

Lovely Vue :heartbeat:


  1. https://jp.vuejs.org/v2/guide/components.html#data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93 

  2. @v-on: の省略記法 

  3. 本質的な解決方法としてはちょっとずれているかもしれませんが、今回はv-modelの紹介が目的のためv-modelを使います 

  4. これは v-bind: の省略記法です。 

5
3
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
5
3