業務でTrelloをよく使うので、Vue.jsを使って同じようなTODOアプリ作れないかなーと思い作成。
部分的に、気になるところを抽出して説明していきたいと思います。
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Document</title><linkrel="stylesheet"href="reset.css"><linkrel="stylesheet"href="style.css"></head><body><divid="app"><divclass="container"><divclass="flexitem item1"><h1>未着手</h1></div><divclass="flexitem item2"><h1>進行中</h1></div><divclass="flexitem item3"><h1>TODOリスト</h1></div><divclass="flexitem item4"><h1>確認待ち</h1></div><divclass="flexitem item5"><h1>完了</h1></div></div></div></body></html>
ベースはhtmlとcss(flexbox)で作りました。ここに、Vue.jsを使ってTODOリストを作成していきます。
<body><divid="app"><p><inputtype="text"placeholder="TODOを入力してください"v-model="newitemtitle"><buttonv-on:click="addbutton">add</button></p><ul><liv-for="(item,index) in items"><label><labelv-bind:class="{ done: item.ischecked }"><inputtype="checkbox"v-model="item.ischecked"> {{ item.title }}
<buttonv-on:click="deletebutton(index)">delete</button></label></li></ul></div></body>
letvm=newVue({el:'#app',data:{items:[],newitemtitle:'',id:0},methods:{addbutton:function(){if(this.newitemtitle==='')return;this.items.push({title:this.newitemtitle,ischecked:false,id:this.id++});this.newitemtitle=''},deletebutton:function(index){if(confirm('本当に削除しますか?')){this.items.splice(index,1)}}}})
<p><inputtype="text"placeholder="TODOを入力してください"v-model="newitemtitle">
で、テキストボックス配置。v-modelで、vueインスタンスのdataオプションの、newitemtitleと紐づけます。
htmlのnewitemtitleに変更があれば、紐づいているjsのnewitemtitleの値も更新されます。
newitemtitle=' 'とすることによって、空の状態でテキストボックスを作成できます。
<buttonv-on:click="addbutton">add</button></p>
で、v-on:clickディレクティブを使い、addボタンをクリックしたときに、addbuttonメソッドが呼ばれます。
下記のメソッドです。
addbutton:function(){if(this.newitemtitle==='')return;this.items.push({title:this.newitemtitle,ischecked:false,id:this.id++});this.newitemtitle=''}
空文字だったらreturnで処理を終了させて、pushメソッドで、配列 items[ ]の中に、テキストボックスで入力した値を追加します。値を追加すると、テキストボックスの中身が空になっていて欲しいので、
this.newitemtitle=''
で、配列に値を追加した後に、テキストボックスの中身を空にします。
ischecked:false
は、
<labelv-bind:class="{ done: item.ischecked }">
と紐づいてくるのですが、ischeckedがtrueだったら、TODOに打ち消し線を引くようにCSSで調整してます。
.done{text-decoration:line-through;}
<liv-for="(item,index) in items"v-bind:key="item.id">
v-bind:key="item.id
配列内のデータを繰り返し表示するのに、なぜv-bind:key="item.id
が必要なのか....
調べたところによると、ただ表示する分にはkeyを与えなくてもいいが、要素の追加や削除、順序変更などがある場合は、要素が意図しない動きをしてしまうため らしいです。今回のTODOアプリはもろ当てはまってます(汗)
各要素ごとに、一意のkeyを設定してあげることにより正しく表示できる、ということですね。
一旦はそれっぽく表示できました。TODOリスト内の要素を、「進行中」や、「完了」へとドラッグ&ドロップで移動できるようにするため、Vue.Draggableというライブラリを使いました。
今回はCDNを使いました。
<liv-for="(item,index) in items"v-bind:key="item.id">
を、
<draggabletag="ul"v-bind:options="{group:'ITEMS'}"><liv-for="(item,index) in items"v-bind:key="item.id"></draggable>
このように囲ってあげると、リスト内で要素の順序変更が行えるようになります。
https://i.gyazo.com/1d49eb621ce87037b510cdb4649d4329.mp4
これ見た目だけは動いてるように見えるけど、データの保存とかどうすんだこれ・・・・
参考にさせていただいた記事
Vue.jsでドラッグ&ドロップするなら「Vue.Draggable」がおすすめ
Vue.js: v-forで項目インデックスをkey属性にしていいのか