はじめに
7/12 修正
記事下部にて、
filter
メソッドを使用している箇所がありましたが、
forEach
の方が適しているとご指摘がありましたので、修正しました。
以前Qiitaの方に投稿した記事ですが、こちらにも投稿します。
少しご指摘もいただいたので、FIX版になります!
Vue.jsの勉強で超簡単なタスク管理アプリを作ってみる
今まで、Vue.jsの記事として下記を投稿してきました。
ただ、今ひとつピンとこなかったため、よくあるTODOアプリを作成してみました。
サンプルはこちらです。
https://jsfiddle.net/naoki85/fo26rmr0/12/
準備
Bootstrapを読み込み
CSSは面倒なので、Bootstrapを使用したいと思います。
JS Fiddleでは、External Resourcesにて読み込むことができます。
CDNのURLを取得し、JS Fiddleの左側、External Resourcesに入力しておきます。
このとき、BootstrapのJSはJQueryを必要とするのでCSSのみにしておきます。
(後でコンソールでエラーが出てしまうので。。。)
HTMLで目的のかたちを作る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <table class="table table-striped"> <thead> <tr> <th>Name</th> <th></th> </tr> </thead> <tbody> <tr> <td>Studying JavaScript</td> <td> <div class="btn btn-danger">Done!</div> </td> </tr> <tr> <td>Studying PHP</td> <td> <div class="btn btn-danger">Done!</div> </td> </tr> <tr> <td>Studying Ruby</td> <td> <div class="btn btn-danger">Done!</div> </td> </tr> <tr> <td><input class="form-control"></td> <td> <div class="btn btn-default">Create Task</div> </td> </tr> </tbody> </table> |
このような感じです。
タスクの一覧表示
Vueインスタンスの作成
1 2 3 4 5 6 7 8 9 10 | var vm = new Vue({ el: '#tasks-index', data: { tasks: [ { id: 1, name: 'Studying JavaScript', isDeleted: false }, { id: 2, name: 'Studying PHP', isDeleted: false }, { id: 3, name: 'Studying Ruby', isDeleted: false }, ] } }) |
後述しますが、TODOの完了は論理削除としますので、プロパティに
isDeleted
をもたせておきます。
v-forとv-ifを使用して条件ループ
まずはテーブルタグの方に
id="tasks-index"
を割り当てておきます。
また、
v-for
で
tasks
の値をループ処理します。
そして、
v-if
で、
isDeleted = true
の値だけ出力するようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <table id="tasks-index" class="table table-striped"> <thead> <tr> <th>Name</th> <th></th> </tr> </thead> <tbody> <tr v-for="task in tasks"> <td>{{ task.name }}</td> <td> <div class="btn btn-danger">Done!</div> </td> </tr> <tr> <td><input class="form-control"></td> <td> <div class="btn btn-default">Create Task</div> </td> </tr> </tbody> </table> |
これで、一覧表示はできましたので、次は新規登録です!
タスクの新規登録
クリックイベントの設定
「Create Task」ボタンが押されたら、
tasks
プロパティに値を追加したいので、クリックイベントを設定します。
v-on:click
を使用すれば、設定したインスタンスメソッドにとばすことができます。
今回は後ほど、
createTask
というメソッドを作りたいと思います。
1 2 3 4 5 6 7 8 9 | <!-- 省略 --> <tr> <td><input v-model="newTask" class="form-control"></td> <td> <div class="btn btn-default" v-on:click="createTask">Create Task</div> </td> </tr> </tbody> </table> |
また、入力フォームとして
input
タグを使用していますが、そこに
v-model
で
newTask
というプロパティをバインディングしています。
新規登録に際し、新しい値をどこかに保持する必要があると考えたのですが、とりあえず新しいインスタンスプロパティを用意し、そこに保持する方法としました。
(このあたりはもっとスマートな方法がありそうです。。。)
インスタンスに追記
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var vm = new Vue({ el: '#tasks-index', data: { tasks: [ { id: 1, name: 'Studying JavaScript', isDeleted: false }, { id: 2, name: 'Studying PHP', isDeleted: false }, { id: 3, name: 'Studying Ruby', isDeleted: false }, ], newTask: '', }, methods: { createTask: function (event) { // 新しいIDを、配列の最後のIDから計算 var new_id = this.tasks[this.tasks.length - 1].id + 1; // 配列に追加 this.tasks.push({ id: new_id, name: this.newTask, isDeleted: false }); // プロパティを空に戻す this.newTask = ''; } } }) |
タスクの完了(論理削除)
前述したように、タスクの完了とは、論理削除とさせていただきます。
クリックイベントの設定
1 | <div class="btn btn-danger" v-on:click="doneTask(task.id)">Done!</div> |
doneTask
メソッドをVueインスタンスに追記したいと思います。
メソッドの追記
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var vm = new Vue({ // 中略 methods: { // 中略 doneTask: function (task_id) { this.tasks.filter(function (task) { if (task.id === task_id) { return task.isDeleted = true; } }) } } }) |
doneTask
メソッドは、引数として
task_id
を受け取ります。
その後、
tasks
プロパティをfilterで処理し、対象のIDの
isDeleted
をtrueにして完了(論理削除)とします。
filterではなくforEachを使用
7/12 追記
filter
メソッドはブロック内を満たす新しい配列を生成するため、今回のように論理削除する場合には
forEach
の方が適しているというご指摘をいただきました。
そのため、
doneTask
メソッドは下記のように修正しました。
1 2 3 4 5 6 7 8 | doneTask: function (task_id) { - this.tasks.filter(function (task) { + this.tasks.forEach(function (task) { if (task.id === task_id) { return task.isDeleted = true; } }) } |
さいごに
簡単ではありますが、勉強用に作成してみました。
まだ公式リファレンスが残っているので、もう少し基本をやり、近いうちにSPAを作って公開したいと思います!