はじめに
こちらは やさしめ Vue.js チュートリアル(1) ~ Vue CLI でプロジェクト作成と Linter の設定 の続きとなります。
今回はデータとイベントの制御について学びます
ハンズオン
1. 余計な記述の削除とタイトルの追加
まずは今回のハンズオン向けに初期状態の余計な記述を削除しましょう。
-
HelloWorld.vue
を削除 -
App.vue
修正- タイトルを追加
- HelloWorld コンポーネントを利用している箇所を削除
- スタイルタグの中身を削除
以下のようになります。
<template>
<div id="app">
<h1>Lovely Vue</h1>
</div>
</template>
<script>
export default {
name: "App"
};
</script>
<style></style>
動作
真っ白な背景にタイトルだけが表示されていれば OK です
ソースコード
https://github.com/taiju59/lovely-vue/commit/b656c9366307fed7a17db2721265ff0e463a22f4
2. 宣言的レンダリング
スクリプト側で定義したデータをtemplate側で表示する方法を学びます。
まず、スクリプト側で data
として message
を定義
export default {
- name: "App"
+ name: "App",
+ data: () => ({
+ message: "Spark joy!"
+ })
};
テンプレート側で {{ message }}
と記述して表示させます。
<div id="app">
<h1>Lovely Vue</h1>
+ {{ message }}
</div>
動作
「Lovely Vue」の下に「Spark joy!」と表示されていれば OK です
ソースコード
https://github.com/taiju59/lovely-vue/commit/275e6229a2aa10400389679d39f7b8929bc7d129
ポイント
-
data
で変数を宣言- ここでは詳しく説明しませんが、
data
は関数でなければなりません1
- ここでは詳しく説明しませんが、
-
{{ }}
で囲めば変数を展開できる
3. ユーザー入力の制御
ユーザーの入力に応じて表示内容を変更してみましょう。
イベントリスナー登録(v-on)
テンプレート側にイベントリスナーを登録しましょう。
input
要素の input
イベントが走ったときに onInput
という名前の関数を呼ぶようにしておきます。
<div id="app">
<h1>Lovely Vue</h1>
+ <input @input="onInput" />
+ <br />
{{ message }}
</div>
このままでは onInput
という関数を呼ぼうとして存在せずエラーとなってしまうので、
スクリプト側に呼ばれるメソッドである onInput
を定義しましょう。
この中で、入力内容を取得し message
を上書きします。
export default {
name: "App",
data: () => ({
message: "Spark joy!"
- })
+ }),
+ methods: {
+ onInput(event) {
+ const text = event.target.value;
+ this.message = text;
+ }
+ }
};
動作
入力欄に入力した内容がその下に表示されるようになっていれば OK です
ソースコード
https://github.com/taiju59/lovely-vue/commit/802a6b6d02d1d2f4f9dede8711715314e5af7eec
ポイント
-
@input
でインプットイベントと関数を紐付け2-
@input
の@
は生の JavaScript でいうaddEventListener
と考えておけば OK
-
-
methods
で関数を宣言 - スクリプト内では
this
のプロパティとしてdata
にアクセスできる
双方向バインディング(v-model)
画面表示時は入力欄の中は空なのに、
入力欄の下には「Spark joy!」が表示されていますね。
なぜこれが起きているのか?というと、
入力内容 => message という方向には連動していますが、
message => 入力内容 という方向には連動していないからです。
これを連動させるため、双方向バインディング(v-model)を用います。3
テンプレート部分の input
の記述を以下のように変更しましょう。
- <input @input="onInput" />
+ <input v-model="message" />
いらなくなっちゃったので、スクリプト部分の onInput
は削除しましょう。
export default {
name: "App",
data: () => ({
message: "Spark joy!"
- }),
+ })
- methods: {
- spark(event) {
- const text = event.target.value;
- this.message = text;
- }
- }
};
動作
表示時に入力欄に「Spark joy!」が入っていて、且つ、
入力内容に連動してその下の文字列が変化するはずです
ソースコード
https://github.com/taiju59/lovely-vue/commit/c312b2c7413630980ef588c0e8bf5722c977759f
ポイント
-
v-model
で入力内容と変数を双方向バインディングできる
4. ループ( v-for
)
いわゆる for 文です。
v-for
を使うことでループでDOMを追加できます。
まず、スクリプト部分で data
に todos
という変数を定義します。
data: () => ({
+ todos: [
+ { id: 1, text: "ときめき" }
+ ],
message: "Spark joy!"
})
テンプレート部分で v-for
を使ってループで表示させます。
<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
になります。
スタイル部分にそれっぽいスタイルも追加しておきましょう。
- <style></style>
+ <style>
+ .task-card {
+ border: solid 1px;
+ margin: 5px;
+ padding: 2px;
+ width: 250px;
+ }
+ </style>
動作
「ときめき」と書かれたカードっぽいやつが表示されているかと思います
ソースコード
https://github.com/taiju59/lovely-vue/commit/19757cc150d98c5b86513c8dc16bad6f1517843e
さらに、タスクを追加できるようにしましょう。
テンプレート側に追加ボタンを記述します。
<input v-model="message" />
+ <button @click="add">追加</button>
<br />
スクリプト側に add
という関数を定義し、この中で新しいタスクを追加します。
- })
+ }),
+ methods: {
+ add() {
+ const newTodo = {
+ id: this.todos.length + 1,
+ text: this.message
+ };
+ this.todos.push(newTodo);
+ this.message = "";
+ }
+ }
};
動作
「追加」ボタンを押すとタスクが追加さるようになっていれば OK です
ソースコード
https://github.com/taiju59/lovely-vue/commit/838eaf5f88deee4b886c26618793c83c020cd2a4
ポイント
-
v-for
でテンプレート内で for 文が回せる-
key
属性にはループ内で一意となる値を設定しましょう(スタイルガイド参照)
-
5. 算出プロパティ( computed
)
気付いちゃった人もいるかもしれませんが、
このままでは入力欄が空でもタスクの追加ができちゃいます。
ダサいので、入力欄が空の場合は追加ボタンを無効化しましょう。
スクリプト部分に computed
とその中に isDisabled
という関数を定義します。
message: "Spark joy!"
}),
+ computed: {
+ isDisabled() {
+ return this.message.length === 0;
+ }
+ },
methods: {
message
が空なら true
を返します。
これをテンプレート部分で使います。
- <button @click="add">追加</button>
+ <button :disabled="isDisabled" @click="add">追加</button>
これで、
入力内容が空の時は isDisabled
が true
=> disabled
が有効化、
入力内容がある時は isDisabled
が false
=> disabled
が無効化
します。
動作
入力欄が空の時に「追加」ボタンが押せなくなっていれば OK です
ソースコード
https://github.com/taiju59/lovely-vue/commit/3778dd29f1d34284eb68861ae973edcbf58c9d28
ポイント
-
computed
で算出プロパティを宣言- 定数や、既存の各変数から自動的に導き出される値を取得するために使います
- 導出元の変数が変化すれば
computed
の結果も変わり、これに応じて DOM も変化します
- HTML 属性に値を指定する際、
:disabled
など:
を前に付けると右辺はスクリプトとして変数が展開されます4
おわりに
Vue の基本についてかいつまんで学びました。
ここまでやれば、小さいものなら何か作れるちゃうかも?と
思ってもらえたかもしれません。
また、リアクティブなフレームワークが初めての人は、
双方向バインディングや算出プロパティで リアクティブの風 を感じてもらえたら嬉しいです。
次回はコンポーネントをファイル分割する方法について学びます。
次回 やさしめ Vue.js チュートリアル(3) ~ コンポーネントによる構成
Lovely Vue
-
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 ↩
-
本質的な解決方法としてはちょっとずれているかもしれませんが、今回はv-modelの紹介が目的のためv-modelを使います ↩
-
これは
v-bind:
の省略記法です。 ↩