【Nuxt.js】todoアプリを作成してみた②

前回の記事はこちら
https://qiita.com/ayapon/items/d93807e7699434279531

<h1>作成の手順</h1>
(1)Nuxt.jsのプロジェクト作成
(2)template作成
(3)store作成
(4)追加機能作成
(5)検索機能作成
(6)削除機能作成
(7)cssファイル作成

今回は(4)以降について書きます。

<h1>(4)追加機能作成</h1>
methodsにinsertを追加し、入力されたtodoをstoreの中にある配列todosに追加します。

```vue:pages/index.vue
<template>
  <section class="container">
    <h1>Todo App</h1>
    <p><input type="text" name="content" v-model="content" /></p>
    <div>
      <button @click="insert">save</button>
      <button>find</button>
    </div>
    <ul>
      <li v-for="(todo, index) in todos" :key="index">
        <span>{{ todo.content }}</span><span>({{ todo.created }})</span><span>×</span>
      </li>
    </ul>
  </section>
</template>

<script>
import {mapState} from 'vuex';

export default {
  data: function() {
    return {
      content: ''
    }
  },
  computed: {
    ...mapState(['todos'])
  },
  methods: {
    insert: function() {
      this.$store.commit('insert', {content: this.content});
      this.content = '';
    }
  }
}
</script>
```

まず、inputタグにv-modelを追加し、入力されたtodoとdataのcontentをデータバインディングします。
そのあと、saveボタンにクリックイベントを設定して、methodsのinsertを呼び出します。
methodsのinsertでは、storeのmutationsのinsertに、引数として入力されたtodoを渡して実行します。
また、todoを追加したら入力欄は空欄になるようにcontentを空にします。

todoを入力→saveボタンを押すと、todoが追加されていると思います。
![(4)sample.png](https://qiita-image-store.s3.amazonaws.com/0/388011/cfaf4694-4e17-3d29-23a3-15746c86d919.png)

<h1>(5)検索機能作成</h1>
検索機能を作成するにあたって、dataにfind_flgを追加します。
そして、find_flgがtrueの場合は検索した結果を、
find_flgがfalseの場合はtodosすべてを表示するように修正します。

```vue:pages/index.vue
<template>
  <section class="container">
    <h1>Todo App</h1>
    <p><input type="text" name="content" v-model="content" @focus="set_flg"/></p>
    <div>
      <button @click="insert">save</button>
      <button @click="find">find</button>
    </div>
    <ul>
      <li v-for="(todo, index) in display_todos" :key="index">
        <span>{{ todo.content }}</span><span>({{ todo.created }})</span><span>×</span>
      </li>
    </ul>
  </section>
</template>

<script>
import {mapState} from 'vuex';

export default {
  data: function() {
    return {
      content: '',
      find_flg: false
    }
  },
  computed: {
    ...mapState(['todos']),
    display_todos: function() {
      if(this.find_flg) {
        var arr = [];
        var data = this.todos;
        data.forEach(element => {
          if(element.content.toLowerCase() == this.content.toLowerCase()) {
            arr.push(element);
          }
        });
        return arr;
      } else {
        return this.todos;
      }
    }
  },
  methods: {
    insert: function() {
      this.$store.commit('insert', {content: this.content});
      this.content = '';
    },
    find: function() {
      this.find_flg = true;
    },
    set_flg: function() {
      if(this.find_flg) {
        this.find_flg = false;
        this.content = '';
      }
    },
  }
}
</script>

```

findボタンにクリックイベントを設定してmethodsのfindを呼び出し、
findボタンが押されたらfind_flgをtrueにします。
そして、computedにdisplay_todosを設定し、find_flgがtrueの場合は新たにarrという配列を用意し、
入力されたtodoがtodosの中にあればarrに追加して、最終的にarrを返します。
find_flgがfalseの場合はtodosすべてを返すようにします。
また、templateのlistの部分もtodos→display_todosに修正します。

これで一通り検索機能はできていますが、検索結果が表示されているとき（find_flgがtrueのとき）に
入力欄にクリックしたら検索を終了してtodosすべてを表示するように、
inputタグの中にfocusを設定してset_flgを呼び出し、find_flgをfalseにするようにします。

「hogehoge」と入力→findボタンを押して、hogehogeのみ表示されていたらOKです。
また、検索結果が表示されている状態で入力欄をクリックすると、
すべてのtodosが表示されることが確認できると思います。

<h1>(6)削除機能作成</h1>
削除機能はmethodsにremoveを追加します。

```vue:pages/index.vue
<template>
  <section class="container">
    <h1>Todo App</h1>
    <p><input type="text" name="content" v-model="content"  @focus="set_flg"/></p>
    <div>
      <button @click="insert">save</button>
      <button @click="find">find</button>
    </div>
    <ul>
      <li v-for="(todo, index) in display_todos" :key="index">
        <span>{{ todo.content }}</span><span>({{ todo.created }})</span><span @click="remove(todo)">×</span>
      </li>
    </ul>
  </section>
</template>

<script>
import {mapState} from 'vuex';

export default {
  data: function() {
    return {
      content: '',
      find_flg: false
    }
  },
  computed: {
    ...mapState(['todos']),
    display_todos: function() {
      if(this.find_flg) {
        var arr = [];
        var data = this.todos;
        data.forEach(element => {
          if(element.content.toLowerCase() == this.content.toLowerCase()) {
            arr.push(element);
          }
        });
        return arr;
      } else {
        return this.todos;
      }
    }
  },
  methods: {
    insert: function() {
      this.$store.commit('insert', {content: this.content});
      this.content = '';
    },
    find: function() {
      this.find_flg = true;
    },
    set_flg: function() {
      if(this.find_flg) {
        this.find_flg = false;
        this.content = '';
      }
    },
    remove: function(todo) {
      this.$store.commit('remove', todo)
    }
  }
}
</script>
```

表示されているtodoそれぞれについている「×」の部分にクリックイベントを設定し、
methodsのremoveを呼び出します。その際、クリックされたtodoを引数として渡します。
methodsのremoveでは、storeのmutationsのremoveに、引数としてクリックされたtodoを渡して実行します。

×を押してクリックすると、「remove (クリックされたtodoの内容)」とアラートが表示され、
クリックされたtodoが削除されると思います。

<h1>(7)cssファイル作成</h1>
cssファイル作成はおまけです。
Nuxt.jsでcssファイルを読み込む方法を書いておきます。

pagesフォルダにstyle.cssを作成し、以下のようにコードを書きます。

```css:pages/style.css
.container {
    width: 400px;
    margin: 100px auto;
    text-align: center;
}

h1 {
    font-size: 32pt;
}

input {
    width: 300px;
    margin: 20px;
    padding: 8px 4px;
    font-size: 16pt;
}

button {
    margin: 0 10px;
    padding: 4px 8px;
    font-size: 10pt;
}

ul {
    margin-top: 20px;
    padding: 0;
    text-align: center;
}

li {
    list-style: none;
    margin: 5px 0;
    font-size: 14pt;   
}

span {
    margin: 0 5px;
}
```

そして、sample-todo-appフォルダ直下にあるnuxt.config.jsのcssの部分を、以下のように修正します。

```js:nuxt.config.js
  /*
  ** Global CSS
  */
  css: [
    'pages/style.css'
  ]

```

これでcssファイルが反映されていると思います。

<h1>おわりに</h1>
引き続きNuxt.jsの勉強がんばりたいです。
初めて記事を書いたので、もし間違った記載などあればご指摘いただけると幸いです。

<h1>参考</h1>
<a href="https://www.amazon.co.jp/Vue-js-Nuxt-js%E8%B6%85%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798056596">Vue.js & Nuxt.js超入門</a>