Todoリスト #2
前回のviewからvueの機能を追加して完成させましょう。
リストを表示する
Todoリストの表示を行なっていきましょう
前回は
<ul> <li> <span>Todo1</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo2</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo3</span> <button>Return</button> <button>Delete</button> </li> </ul>
上記のcodeをv-forを使用したcodeに変えていきましょう
そのためにApp.vueからComplete.vueにリストを渡しましょう。
<div> <p>imcomplete</p> <div> <Incomplete :list="imcompleteList" /> </div> </div>
そしてdataにimcompleteListを定義しましょう
data() { return { imcompleteList: [] }; }
受け取る側
props: { list: { type: Array, default: () => [] } },
そしてtemplate側で
<ul> <li v-for="(item, i) in list" :key="i"> <span>{{ item }}</span> <button>Return</button> <button>Delete</button> </li> </ul>
とします
仮にlistに
['Todo1', 'Todo2', 'Todo3']
となっていた場合はv-forにて
<ul> <li> <span>Todo1</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo2</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo3</span> <button>Return</button> <button>Delete</button> </li> </ul>
な結果となります
li配下をループして各中身をitem, indexをiとしてます
こちらをIncomplete, Complete両方に適応させましょう。
- dataの配列は別々にしてtemplate側でも渡す値を別にしましょう script
data() { return { imcompleteList: [], completeList: [] }; }
template
<div> <p>complete</p> <div> <Complete :list="completeList" /> </div> </div>
Inputで入力した値を反映させる
今のままだと、inputに入力した値はどこにも反映されません。
なので入力した値を反映させます
inputタグにはv-modelを利用することによりscript側で値を取得することができます。
<input v-model="todo" type="text">
script側にも
data() { return { todo: "", imcompleteList: [], completeList: [] }; },
次にAdd Todoボタンを押したら、入力した値をimcompleteListに追加しましょう
template側のボタンではv-on:clickもしくは@clickを使用して、ボタンをclickした時を検知します
<button @click="addTodo">Add Todo</button>
この時にaddTodoというのはscript側に定義してあります。
methods: { addTodo() { this.imcompleteList.push(this.todo); // reset this.todo = ""; } }
this.todoというのはdata内のtodoのことです
imcompleteListに追加した後にtodoをリセットすることによりinput内の入力された値を消してます
imcompleteListに追加したことにより、Incompleteが再描画されて追加されているかと思います
imcompleteListを完了に持っていく
Completeボタンを押したら対象のTodoをCompleteに移動させます
まずはCompleteボタンを押したら発火するmethodを作成しましょう
<li v-for="(item, i) in list" :key="i"> <span>{{ item }}</span> <button @click="completeTodo(i)">Complete</button> <button>Delete</button> </li>
script
methods: { completeTodo(i) { this.$emit("complete", i); }, }
emitという新しいものが出てきました
emitは子コンポーネントから親コンポーネントに対して、eventを送ることができます
親コンポーネントであるApp.vueをこのようにしてみましょう
<Incomplete :list="imcompleteList" @complete="completeTodo" />
script
methods: { completeTodo(i) { // 対象のTodoを取得 const todo = this.imcompleteList[i]; // 対象のTodoをcompleteListに追加 this.completeList.push(todo); // imcompleteListから対象のTodoを削除 this.imcompleteList.splice(i, 1); }, }
emitの第1引数にevent名, そのあとは引数を入れることができます
こちら同じ要領でComplete TodoからImcomplete Todoに移してみましょう
Todoを削除する
最後に削除機能を追加します
今までのことを活かしてみましょう
Deleteボタンを押した際に発火するmethodを定義します
<li v-for="(item, i) in list" :key="i"> <span>{{ item }}</span> <button @click="imcompleteTodo(i)">Return</button> <button @click="deleteTodo(i)">Delete</button> </li>
script
methods: { deleteTodo(i) { this.$emit("delete", "complete", i); } }
App側で受け取る記述をしましょう
<Complete :list="completeList" @imcomplete="imcompleteTodo" @delete="deleteTodo"/>
script
methods: { deleteTodo(type, i) { if (type === "imcomplete") { this.imcompleteList.splice(i, 1); } else if (type === "complete") { this.completeList.splice(i, 1); } } }
以上である程度の機能は作れたかと思います。
サンプルはこちらになります
Todoリスト #1
まずviewから作成します。
=> vueの機能をあまり使用せずに見た目を作成します。
ファイル構成
今回はシンプルにします。
components --- Complete.vue // 完了したTodoリスト |- Imcomplete.vue // 未完了のTodoリスト App.vue
こちらの2ファイルを使用します。
App.vueにTodoを入力するInputを作成
<div> <input type="text"> <button>Add Todo</button> </div>
各componentにTodoリストを作成
3つほどTodoを作成してみましょう
components/Complete.vue
<ul> <li> <span>Todo1</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo2</span> <button>Return</button> <button>Delete</button> </li> <li> <span>Todo3</span> <button>Return</button> <button>Delete</button> </li> </ul>
components/Imcomplete.vue
<ul> <li> <span>Todo1</span> <button>Complete</button> <button>Delete</button> </li> <li> <span>Todo2</span> <button>Complete</button> <button>Delete</button> </li> <li> <span>Todo3</span> <button>Complete</button> <button>Delete</button> </li> </ul>
App.vueから各componentを呼び出す
<template> <div id="app"> <div> <input type="text"> <button>Add Todo</button> </div> <div class="flex"> <div> <p>imcomplete</p> <div> <Incomplete /> </div> </div> <div> <p>complete</p> <div> <Complete /> </div> </div> </div> </div> </template> <script> import Incomplete from "./components/Imcomplete"; import Complete from "./components/Complete"; export default { name: "App", components: { Incomplete, Complete } }; </script> <style> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .flex { display: flex; justify-content: space-around; } .flex > div { width: 45%; } </style>
ここまででviewの部分は完成しました。
次回はvueの機能を使いながら完成を目指していきましょう。
.vueファイルの書き方
.vueファイルの書き方
<template> // ここにHTMLを記述 </template> <script> export default { // ここにVue Scriptを記述 } </script> <style> // ここにCSSを記述 </style>
別の.vueファイルを読み込む
<script> import VueFile from "相対パス" export default { components: { VueFile } } </script>
ファイルが増える場合はコンマ区切りで追加していく
Todoリストを作ってみる
CodeSandboxでTodoリストを作ってみましょう
ここで学んだことを活かせれば作れるはず
大まかな仕様
・input tagにTodoを入力する
・Add Todo ボタンをクリックしたらimcomplete領域に表示する
・imcomplete領域にあるTodoのComplete ボタンをクリックしたら、
そのTodoをcomplete領域に移動する
・complete領域にあるTodoのReturn ボタンをクリックしたら、
そのTodoをimcomplete領域に移動する
・Delete ボタンをクリックしたら、そのTodoを削除する
Vue的な仕様
・imcomplete, complete領域にあるTodoリストはそれぞれ別Componentを作成してみる
かなりシンプルなTodoリストですが、基礎には良い感じになると思います
ポイント
・input tagに入力されたTodoのdataを取得
・各ボタンのイベントを発火する
・TodoリストをLoopさせて表示させる
・Todoリストの追加や削除に伴うdataの扱い
次回から解説しながら作っていきます
Vue CLI
自分のPCに入れたくない人はここで開発するのが良いかも
CodeSandbox: Online IDE for Rapid Web Development
Vue CLIのインストール
$ npm install -g @vue/cli
プロジェクト作成
$ vue create vue-project
色々質問があるけど、今回は適当に
$ cd vue-project $ npm run serve
http://localhost:8080
にアクセス
Vueの基礎
Hello World
https://jsfiddle.net/shogo_t2525/w5m9qLd8/
・elオプションにDOMを指定
・dataオプションにリアクティブにするオブジェクト
リアクティブ
https://jsfiddle.net/shogo_t2525/w5m9qLd8/
オブジェクトの変更を検知してhtmlの表示を更新する
dataにあるもの => リアクティブ
constなど => 非リアクティブ
ディレクティブ
https://jsfiddle.net/shogo_t2525/Ls7o8mrb/
・v-から始まる特別な属性
・ディレクティブを使うことで様々な機能が利用可能
v-bind, v-for, v-if, v-onなど...
v-bind は省略可能
v-on は @に省略可能
コンポーネント
コンポーネント => 部品と思ってもらえればOK
毎回記述するのは面倒なので部品化しちゃいましょうって話
https://jsfiddle.net/shogo_t2525/6hscb41y/
・データの受け渡し
親コンポーネントから子コンポーネントはpropsにてデータを渡すことができる
子コンポーネントから親コンポーネントに何かしたい場合はemitを使用する
computed
算出プロパティ => わかりにくい...
https://jsfiddle.net/shogo_t2525/0vzf2Lk3/
つまり
・computedで宣言されたものはcacheして保持する
・computed内のリアクティブなdataが変更された場合に再計算を行う