はじめに
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 | varvm=newVue({ 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> <trv-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><inputv-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 | varvm=newVue({ 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から計算 varnew_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 | varvm=newVue({ // 中略 methods:{ // 中略 doneTask:function(task_id){ this.tasks.filter(function(task){ if(task.id===task_id){ returntask.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を作って公開したいと思います!