【Nuxt.js】ちょ〜簡単！TODOリスト

# 前置き

![picture_pc_e707cf860502e0ddeeeecda8740b1f6d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/90c93ae7-cd3a-eead-785e-b37df9c92d76.gif)

簡単TODOリストを作ります！
TODO追加、終わったら削除するだけの
超絶シンプルなリストです。
そのためスタイリングはほとんどしません。

今まで記事にしてきた、
slot・props・$emit全てを使うので
総復習ができます✍️
早速作ってみましょう！！♪
詰まったら各要素の記事を読んで
マスターしてくださいね🌟

【コンポーネント構成】
・TODO入力する部分
・リスト表示部分
・リストの進捗率表示

【データの扱い方】
親を介して、
・入力したデータをリスト表示させる
・データの個数に合った進捗率を表示させる

【ディレクトリ の構造、ファイル名】

```bash:file

components/
-----| Form.vue (TODO入力)
-----| ListItem.vue (リスト)
-----| List.vue (リストの繰り返し)
-----| Progressbar.vue (進捗率)

pages/
--| index.vue
```

# Step1： リスト表示部分の作成
【コンポーネント】
・リストの箱 (ListItem.vue)
・それを繰り返すもの (List.vue)
の2つを用意し
親からデータを渡します！
【使う物】
・slot
・props
【List.vue】
まず箱だけのListItem.vueを作成！
箱の中に表示されるTODOは
**テキストのみ表示できれば良いので
propsではなくslotです。**

```ListItem.vue
ListItem.vue // リストを表示する箱
<template>
 <div class="list-item">
   <slot />
 </div>
</template>

<script>
</script>

<style lang="scss" scoped>
</style>
```

【List.vue】
ListItem.vueを繰り返します。
**ここでtodosという配列を渡したいですね。
propsの出番です！**

```List.vue
List.vue // リストを繰り返して表示させる物
<template>
 <div class="list">
   <ListItem
    v-for="todo in todos"
   >
     {{ todo }}
   </ListItem>
 </div>
</template>

<script>
import ListItem from '~/components/ListItem.vue'

export default {
 components: {
   ListItem
 },
 props: ['todos'],
}
</script>

<style lang="scss" scoped>
</style>
```

【index.vue】
子に渡したpropsのtodosを
親でもtodosと命名しています。
親のdata内todos: ['TODOを作る']が
List.vueのslotで反映されます！

```index.vue
index.vue // 親ページ
<template>
 <div class="page">
   <List
    :todos="todos"
   />
 </div>
</template>

<script>
import List from '~/components/List.vue'

export default {
 components: {
   List
 },
 data () {
   return {
     todos: ['TODOを作る'],
   }
 },
}
</script>

<style lang="scss">
</style>
```

# Step2：TODO入力部分の作成
【コンポーネント】
・Form.vue
【使う物】
・$emit
【Form.vue】
**子自身でリストを追加するという
イベントがあるため$emitを使います。**
v-modalで表示させたいdataごと
親に渡します。
リスト追加する際、
イベント修飾子preventを使わないと
クリックした瞬間リロードされてしまいます。
https://jp.vuejs.org/v2/guide/events.html#イベント修飾子

```Form.vue
Form.vue // 入力フォーム
<template>
 <div class="form">
   <form @submit.prevent="todoAdd">
     <label>やること</label>
     <input v-model="todo">
     <button type="submit">Add</button>
   </form>
 </div>
</template>

<script>
export default {
 data () {
   return {
     todo: '',
   }
 },
 methods: {
   todoAdd () {
     this.$emit('todoAdded', this.todo);
     this.todo = '';
   }
 },
}
</script>

<style lang="scss" scoped>
</style>
```

【index.vue】
子のtodoAddedが起きた時
親ではnewTodoを実行
親data内のtodosに子から受け取った
todoを追加していきます。

配列の変化は公式のこちらをご覧ください。
配列に追加したければpush、
逆に削除したければsplice、です！
https://jp.vuejs.org/v2/guide/list.html#変更メソッド

```index.vue
index.vue // 親ページ
<template>
 <div class="page">
   <Form @todoAdded="newTodo" />
   <List class="todos" :todos="todos"/>
 </div>
</template>

<script>
import List from '~/components/List.vue'
import Form from '~/components/Form.vue'

export default {
 components: {
   List,
   Form
 },
 data () {
   return {
     todo: ['TODOを作る'],
   }
 },
 methods: {
   newTodo (todo) {
     this.todos.push(todo);
   }
 },
}
</script>

<style lang="scss">
</style>
```

# Step3：TODO完了後に削除できるようにする
【コンポーネント】
・ListItem.vue
・List.vue
【使う物】
・$emit
todoを押したら、
該当todoが消えるようにしましょう！
Listコンポーネントで
クリックすれば消えるイベントを作成し、
該当する配列番号(index)を消します！
【ListItem.vue】

```ListItem.vue
ListItem.vue // リストを表示する箱
<template>
 <div class="list-item" @click="$emit('deleteTodo')">
   <slot />
   <button >delete</button>
 </div>
</template>

<script>
</script>

<style lang="scss" scoped>
</style>
```

【List.vue】
deleteTodoイベントを受け取り
親から渡されたpropsの
todosの配列番号のうち1つを消します。

```List.vue
List.vue // リストを繰り返して表示させる物
<template>
 <div class="list">
   <ListItem
     class="list"
     v-for="(todo, index) in todos"
     @deleteTodo="todos.splice(index, 1)"
   >
     {{ todo }}
   </ListItem>
 </div>
</template>

<script>
import ListItem from '~/components/ListItem.vue'

export default {
 components: {
   ListItem
 },
 props: ['todos'],
 methods: {
   deleteTodo (index) {
     this.$emit('deleted', index)
   }
 },
}
</script>

<style lang="scss" scoped>
</style>
```

# Step4：Progressbarの作成
【コンポーネント】
・Progressbar
【使う物】
・props
【Propgressbar.vue】
数値とバーをtodosの個数によって変動させます。
max値を10として、
今10分の何個TODOがあるのか
確認できるようにしましょう。

```Progressbar.vue
Progressbar.vue // 進捗バー
<template>
 <div class="progressbar" :style="{width: (count / max ) * 100 + '%'}">
   {{ count }} / {{ max }}
 </div>
</template>

<script>
export default {
 props: ['count', 'max']
}
</script>

<style lang="scss" scoped>
</style>
```

【index.vue】
countはtodosの長さ＝配列個数
max値は10

```index.vue
index.vue // 親ページ
<template>
 <div class="page">
   <Progressbar
     :count="todos.length"
     :max="max"
   />
   <Form @listAdded="newTodo" />
   <List class="list" :todos="todos" />
 </div>
</template>

<script>
import List from '~/components/List.vue'
import Form from '~/components/Form.vue'
import Progressbar from '~/components/Progressbar.vue'

export default {
 components: {
   List,
   Form,
   Progressbar,
 },
 data () {
   return {
     todos: ['TODOを作る'],
     max: 10,
   }
 },
 methods: {
   newTodo (todo) {
     this.todos.push(todo);
   },
 },
}
</script>

<style lang="scss">
</style>
```

できましたか？🌟
slot, props, $emit全てクリアですね！
おめでとうございます🎉




**このアカウントでは
Nuxt.js、Vue.jsを誰でも分かるよう、
超簡単に解説しています🎈😀
これからも発信していくので、
ぜひフォローしてください♪**
https://twitter.com/aLizlab