【VueCLI3.0】Todoアプリをつくる（Vuetify使用）

Vue.jsでTodoアプリをつくってみたので
覚書も兼ねて、まとめておきます。

# 完成図
![Todoキャプチャ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/f761b273-8b12-d5a6-1595-f4962321da0e.jpeg)


# 環境設定
①npde.js最新版インストール: https://nodejs.org/ja
※ここではv11.14.0


②Vue CLIをグローバルインストール
```$ npm install -g @vue/cli```
※ここではv3.6.3

# プロジェクト新規追加
①Vue CLIプロジェクト作成
```$ vue create <プロジェクト名>```
どちらかを選択
１．```default```（ルーティングなし）
２．```Manually select features```（ルーティングあり）


②Vue CLIプロジェクト実行
```$ npm run serve```


# ここからTodoアプリ作成
今回はVuetifyというプラグインを利用する方法を紹介します。
①ドキュメントルート内にプロジェクト新規作成
プロジェクト名は仮で「todoapp」とします
```$ vue create todoapp```


②ルーティングが必要なので
```Manually select features```を選択
```rooter```を選択
※他の質問はデフォルトでOK


③Vuetifyプラグイン追加
```$ cd todoapp```
```$ vue add vuetify```
※質問は全てデフォルトでOK


# 各ファイルを追加/編集
①TodoFormコンポーネント作成

```src/components/TodoForm.vue
<template>
    <div>
        <v-toolbar dark color="indigo">
            <router-link to="/">
                <v-icon>arrow_back</v-icon>
            </router-link>
            <v-toolbar-title class="white--text">
                My Todo
            </v-toolbar-title>
        </v-toolbar>
        <v-text-field v-model="newTodo" placehlder="Input here..."></v-text-field>
        <v-btn dark color="indigo" v-on:click="addTodo()" class="white--text">
            ADD
        </v-btn>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                newTodo: ''
            }
        },
        methods: {
            addTodo() {
                if(this.newTodo === '') return;
                const todos = JSON.parse(localStorage.getItem('todos')) || [];
                todos.push(this.newTodo);
                localStorage.setItem('todos', JSON.stringify(todos));
                this.newTodo = '';
                this.$router.push('/');
            }
        }
    }
</script>
<style scoped>
a {
    text-decoration: none;
}
</style>
```

②TodoListコンポーネント作成

```src/components/TodoList.vue
<template>
    <div>
        <v-toolbar dark color="indigo">
            <v-toolbar-title class="white--text">
                My Todo
            </v-toolbar-title>
        </v-toolbar>
        <v-list>
            <template v-for="(todo, i) in todos">
                <v-list-tile v-bind:key="i">
                    <v-list-tile-content>
                        {{ todo }}
                    </v-list-tile-content>
                    <v-list-tile-action>
                        <v-btn flat icon v-on:click="deleteTodo(i)">
                            <v-icon>delete</v-icon>
                        </v-btn>
                    </v-list-tile-action>
                </v-list-tile>
                <v-divider v-bind:key="i"></v-divider>
            </template>
        </v-list>

        <div class="bittom-right">
            <v-btn fab color="indigo" v-on:click="addTodo">
                <v-icon color="white">add</v-icon>
            </v-btn>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                todos: []
            }
        },
        created() {
            this.todos = JSON.parse(localStorage.getItem('todos')) || [];
        },
        methods: {
            deleteTodo(i) {
                this.todos.splice(i, 1);
                localStorage.setItem('todos', JSON.stringify(this.todos));
            },
            addTodo() {
                this.$router.push('/todos/add');
            }
        }
    }
</script>

<style scoped>

.bottom-right {
    position: fixed;
    bottom: 0;
    right: 0;
}

</style>
```

③親コンポーネント修正

```src/App.vue
<template>
  <router-view></router-view>
</template>
```

④ルーティング設定

```src/router.js
import Vue from 'vue'
import Router from 'vue-router'
import TodoList from './components/TodoList'
import TodoForm from './components/TodoForm'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      component: TodoList
    },
    {
      path: '/todos/add',
      component: TodoForm
    }
  ]
})
```


# Material Iconsのオフライン対応
モバイル端末でアプリを実行する場合、ネットワークに接続できない状況が発生します。そのためMaterial Iconsをオフラインに設定する必要があります。

①Material Iconsインストール
``` $ npm install material-icons ```


②main.js内1行追加

``` src/main.js
import Vue from 'vue'
import './plugins/vuetify'
import 'material-icons/iconfont/material-icons.css' // 追加
import App from './App.vue'
import router from './router'
```


②index.html２行分削除

```public/index.html
<!-- 削除 / コメントアウト -->
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons"> -->
```