Vue.jsで作るtodoアプリ

#Vue.jsで作るtodoアプリ

前回の記事はこちら
[Vue.js　ディレクティブの基礎２](https://qiita.com/fumiya0414/items/281567d91dbd1c522fad)

これまで紹介したディレクティブを使って
簡単なtodoアプリを作ってみましょう。
[jsfiddle](https://jsfiddle.net/)で実際に記述しながら読むことをおすすめします。
下記が完成品です。

[![Image from Gyazo](https://i.gyazo.com/d700c796da15c1b809edb3dbeced5972.gif)](https://gyazo.com/d700c796da15c1b809edb3dbeced5972)

ページのリロードをせずにタスクの追加・完了・削除ができよう実装します。
※タスクの保存はしない仕様とします。

##空のVueインスタンスとテンプレートの作成

まずはhtmlとjsシートに下記を準備します。
※[jsfiddle](https://jsfiddle.net/)を使用してコード部分のみ記述します。

```html:index/html
<div id="app">

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
	el:'#app',
  
})
```

##要素の配置とイベントハンドリング

```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text">
  <button v-on:click="addItem">Add</button>
</form>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  methods:{
    addItem:function(event){
      alert();
    }
  }
})
```

[![Image from Gyazo](https://i.gyazo.com/1ed10047b8e92fabbb8d4f503a5721b9.gif)](https://gyazo.com/1ed10047b8e92fabbb8d4f503a5721b9)

デバッグのためにalertを記述して動作確認します。
alertダイアログが表示されます。

formのsubmitイベントでページのリロードを無効にするため
formタグにイベント修飾子preventを追記しておきましょう。

##inputタグの中身を双方向データバインディングする

```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text" v-model="newItem">
  <button v-on:click="addItem">Add</button>
</form>

<pre>{{ $data }}</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  data:{
    newItem:""
  },
  methods:{
    addItem:function(event){
    alert();
    }
  }
})
```
[![Image from Gyazo](https://i.gyazo.com/e5bb2c143cf2cb66802be918042eac4f.gif)](https://gyazo.com/e5bb2c143cf2cb66802be918042eac4f)

v-modelディレクティブでinputタグの中身をバインディングします。
デバッグ用にpreタグを使用してdataオプションの中身を確認しましょう。

##タスクの追加
次に空の配列を用意しAddボタンのクリックイベントで
タスクを配列に格納していきます。

```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text" v-model="newItem">
  <button v-on:click="addItem">Add</button>
</form>

<pre>{{ $data }}</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  data:{
    newItem:"",
    todos:[]
  },
  methods:{
    addItem:function(event){
      //alert();
      if(this.newItem == '')return; //タスク未入力の場合は追加しない
      var todo = {
      	item: this.newItem
      };
      this.todos.push(todo);
      this.newItem = '' //タスク追加後に入力欄を空にする
    }
  }
})

```
[![Image from Gyazo](https://i.gyazo.com/ed2fbd99e4d6518e600d129f40106f27.gif)](https://gyazo.com/ed2fbd99e4d6518e600d129f40106f27)

dataオプションに空の配列todosを作成し
addItemメソッド内でinputタグの中身を
todoとして取得してtodosの配列へ格納しています。

task入力後にinput欄をクリアしておきましょう。
合わせてタスク未入力の場合は追加ができないようif文を記述しましょう。

##タスクのリスト表示

```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text" v-model="newItem">
  <button v-on:click="addItem">Add</button>
</form>

<ul>
  <li v-for="todo in todos">{{todo.item}}</li> <!--配列の中身を１つずつ取得-->
</ul>

<pre>{{ $data }}</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  data:{
    newItem:"",
    todos:[]
  },
  methods:{
    addItem:function(event){
    //alert();
    if(this.newItem == '')return;
    var todo = {
      item: this.newItem
    };
    this.todos.push(todo);
    this.newItem = ''
    }
  }
})
```

[![Image from Gyazo](https://i.gyazo.com/66ed8d89234bdfccea385dcd17ef317f.gif)](https://gyazo.com/66ed8d89234bdfccea385dcd17ef317f)

v-forディレクティブをliタグに設定して配列の中身を取得します。

##タスクの管理とスタイルの設定
```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text" v-model="newItem">
  <button v-on:click="addItem">Add</button>
</form>

<ul>
  <li v-for="todo in todos">
  <input type="checkbox" v-model="todo.isDone"><!--チェックボックス同期-->
  <span v-bind:class="{done: todo.isDone}">{{todo.item}}</span><!--classの追加-->
  </li>
</ul>

<pre>{{ $data }}</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  data:{
    newItem:"",
    todos:[]
  },
  methods:{
    addItem:function(event){
      //alert();
      if(this.newItem == '')return;
      var todo = {
        item: this.newItem,
        isDone:false
      };
      this.todos.push(todo);
      this.newItem = ''
    }
  }
})
```

```css:index.css
#app ul{
  list-style:none;
}

#app li > span.done{
  text-decoration:line-through;
}
```
[![Image from Gyazo](https://i.gyazo.com/c90bdb7795b53f1093e7adf57dd1f4eb.gif)](https://gyazo.com/c90bdb7795b53f1093e7adf57dd1f4eb)

タスクにチェックボックスを設定しv-modelディレクティブで
ステータスをisDoneと同期します。

isDoneのステータスによってclassが付与されるよう
v-bindディレクティブでclassをバインディングしましょう。

classの付与によって打ち消し線が表示されるようCSSを記述しました。

##タスクの削除
```html:index/html
<div id="app">
<h2>TODO List</h2>

<form v-on:submit.prevent>
  <input type="text" v-model="newItem">
  <button v-on:click="addItem">Add</button>
</form>

<ul>
  <li v-for="(todo,index) in todos"> <!--indexを引数に追加-->
  <input type="checkbox" v-model="todo.isDone">
  <span v-bind:class="{done: todo.isDone}">{{todo.item}}</span>
  <button v-on:click="deleteItem(index)">Delete</button>　<!--indexを引数に指定-->
  </li>
</ul>

<pre>{{ $data }}</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
  el:'#app',
  data:{
    newItem:"",
    todos:[]
  },
  methods:{
    addItem:function(event){
      if(this.newItem == '')return;
      var todo = {
      	item: this.newItem,
        isDone:false
      };
      this.todos.push(todo);
      this.newItem = ''
    },
    deleteItem:function(index){ //indexを引数に指定
      this.todos.splice(index,1) //indexで指定された要素を1つ削除
    }
  }
})
```
[![Image from Gyazo](https://i.gyazo.com/eec108c0cf0e4c804243c7d06aa3f94d.gif)](https://gyazo.com/eec108c0cf0e4c804243c7d06aa3f94d)

以上でtodoアプリは完成となります。
タスクの追加、完了、削除の動作確認をして
問題なければデバッグ用のpreタグを消しておきましょう。

次回はテンプレート構文です。
[Vue.jsテンプレート構文](https://qiita.com/fumiya0414/items/0a467af7ca6e9eb0f886)