LoginSignup
32
17

More than 5 years have passed since last update.

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

Posted at

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

作成の手順

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

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

(4)追加機能作成

methodsにinsertを追加し、入力されたtodoをstoreの中にある配列todosに追加します。

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

(5)検索機能作成

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

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が表示されることが確認できると思います。

(6)削除機能作成

削除機能はmethodsにremoveを追加します。

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が削除されると思います。

(7)cssファイル作成

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

pagesフォルダにstyle.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の部分を、以下のように修正します。

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

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

おわりに

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

参考

Vue.js & Nuxt.js超入門

32
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
17