Help us understand the problem. What is going on with this article?

Vue CLIでシンプルなTodoリストを作成するハンズオン①

はじめに

Vue CLIを使って、シンプルなTodoを作成しながらVuejsを理解するサンプルが欲しくて作成しながらメモしたことを残しておきます。

前提として、以下の素晴らしい記事の内容を終えている前提で、以下の記事で紹介されているシンプルなTodoをVueCLIで作っていくという内容になります。

  1. Vue.jsミニハンズオン(TODOリスト作成)
  2. Vue.jsミニハンズオン(TODOリストにアニメーションをつける)
  3. Vue.jsミニハンズオン(TODOリストをコンポーネント化する)

自分が色々試した結果上記記事がとてもわかりやすく最短であると感じました。
作成いただいた @moonglows76 さんありがとうございます!!!

煩わしいことは書かず、とりあえずVueを触ってみる程度の温度感ですので、悪しからず...

環境

  • Nodejs 11.1.0
  • VueCLI 4.0.5
  • Yarn 1.19.2

アプリケーションの作成

$ vue create vue-cli-todo-app

$ cd vue-cli-todo-app

作成と同時に以下のファイルを削除します。

  • src/components/HelloWorld.vue
  • assets/logo.png

src/App.vueを以下のように編集します。

<template>
  <div>
    <h1>Hello World</h1>
  </div>
</template>

<script>

export default {

}
</script>

ここまで編集したら、以下を実行して、ローカルサーバーを立ち上げましょう。

$ yarn serve

// yarnをインストールしていない場合はnpmでも起動できます。
$ npm run serve

起動されたら、http://localhost:8080/にアクセスすると、HelloWorldがブラウザに表示されるかと思います。

データバインディングを体験する

src/App.vueを以下のように変更します。

<template>
  <div id="app">
    <h1>MyTodoApp</h1>
    <div>
      <label for="title">タイトル:</label>
      <input type="text" v-model="title" placeholder="タイトル">
    </div>
    <div>
      <label for="body">内容:</label>
      <textarea v-model="body" placeholder="内容"></textarea>
    </div>
    <pre>
      {{$data}}
    </pre>
  </div>
</template>

<script>

export default {
  data: () => ({
    title: '',
    body: ''
  }),
};
</script>

以下のような pre は視覚的にdataの中身を見やすいように配置しています。

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

リストを作成する

src/App.vueを以下のように変更して、ブラウザを確認する。

<template>
  <div id="app">
    <h1>MyTodoApp</h1>
    <div>
      <label for="title">タイトル:</label>
      <input type="text" v-model="title" placeholder="タイトル">
    </div>
    <div>
      <label for="body">内容:</label>
      <textarea v-model="body" placeholder="内容"></textarea>
    </div>
    <ul v-for="list in lists">
      <li>{{ list.title }}</li>
    </ul>
    <pre>
      {{$data}}
    </pre>
  </div>
</template>

<script>

export default {
  data: () => ({
    lists: [
      {title: 'mytodo', body: 'contentcontent'}
    ]
  }),
};
</script>

すると、Elements in iteration expect to have 'v-bind:key' directivesのようにエラーが表示されるかと思います。

v-for ディレクティブでは処理する配列に対して一意なユニークキーを設定しなければいけないというルールがあるからです。

以下のように変更しましょう。

<template>
  <div id="app">
    <h1>MyTodoApp</h1>
    <div>
      <label for="title">タイトル:</label>
      <input type="text" v-model="title" placeholder="タイトル">
    </div>
    <div>
      <label for="body">内容:</label>
      <textarea v-model="body" placeholder="内容"></textarea>
    </div>
    <ul v-for="(list, i) in lists" v-bind:key="i">
      <li>id: {{i}}, title: {{ list.title }}</li>
    </ul>
    <pre>
      {{$data}}
    </pre>
  </div>
</template>

<script>

export default {
  data: () => ({
    lists: [
      {title: 'mytodo', body: 'contentcontent'},
      {title: 'hogehoge', body: 'yuuyuuyuyuyu'}
    ]
  }),
};
</script>

v-forで配列のindexを取得するように変更し、エラーは解消されました。

Todoを追加出来るようにする

src/App.vueを変更します。

<template>
  <div id="app">
    <h1>MyTodoApp</h1>
    <div>
      <label for="title">タイトル:</label>
      <input type="text" v-model="title" placeholder="タイトル">
    </div>
    <div>
      <label for="body">内容:</label>
      <textarea v-model="body" placeholder="内容"></textarea>
    </div>
    <div>
      <input type="submit" value="追加" @click="addList">
    </div>
    <ul v-for="(list, i) in lists" v-bind:key="i">
      <li>id: {{i}}, title: {{ list.title }}</li>
    </ul>
    <pre>
      {{$data}}
    </pre>
  </div>
</template>

<script>

export default {
  data: () => ({
    lists: [
      {title: 'mytodo', body: 'contentcontent'},
      {title: 'hogehoge', body: 'yuuyuuyuyuyu'}
    ],
    title: '',
    body: ''
  }),
  methods: {
    // Todoの追加
    addList: function(){

      this.lists.push({title: this.title, body: this.body})
      this.title = ''
      this.body = ''
    }
  }
};
</script>

<input type="submit" value="追加" @click="addList"> をテキストエリアの下に追加して、サブミットボタンを作成します。

そして、以下で実行するメソッドを作成します。

methods: {
  // Todoの追加
  addList: function(){
   // 簡易なバリデーション
   if(this.title === '' || this.body === '') return

    // dataオプションのlists配列にv-modelから取得したデータを追加する
    this.lists.push({title: this.title, body: this.body})
    // 追加し終わったら、フォームのvalueを空にする
    this.title = ''
    this.body = ''
  }
}

削除メソッドを追加する

src/App.vueを以下のように変更します。

<template>
  <div id="app">
    <h1>MyTodoApp</h1>
    <div>
      <label for="title">タイトル:</label>
      <input type="text" v-model="title" placeholder="タイトル">
    </div>
    <div>
      <label for="body">内容:</label>
      <textarea v-model="body" placeholder="内容"></textarea>
    </div>
    <div>
      <input type="submit" value="追加" @click="addList">
    </div>
    <ul v-for="(list, i) in lists" v-bind:key="i">
      <li>id: {{i}}, title: {{ list.title }} <button @click="deleteList(i)">削除</button></li>
    </ul>
    <pre>
      {{$data}}
    </pre>
  </div>
</template>

<script>

export default {
  data: () => ({
    lists: [
      {title: 'mytodo', body: 'contentcontent'},
      {title: 'hogehoge', body: 'yuuyuuyuyuyu'}
    ],
    title: '',
    body: ''
  }),
  methods: {
    // リストの追加
    addList: function(){
      if(this.title === '' || this.body === '') return

      this.lists.push({title: this.title, body: this.body})
      this.title = ''
      this.body = ''
    },
    // リストの削除
    deleteList: function(i){
      this.lists.splice(i,1)
    }
  }
};
</script>

li 要素内に buttonを追加し削除出来るボタンを配置し、methodsにdeleteListを追加しています。
削除を行うときに、ロジックとしては配列からn番目の要素を削除するというロジックで実装するため、メソッドに対して、配列のindex番号を渡してあげる必要があります。

なので、<li>id: {{i}}, title: {{ list.title }} <button @click="deleteList(i)">削除</button></li>@click="deleteList(i)" でdeleteListメソッドの引数にi(インデックス番号)を渡しています。

引数で渡されたインデックス番号を使用して、spliceで配列から除外したら削除機能は完成です。

完成形はこちらに置いておきます。
https://github.com/ken-sayama/vue-cli-todo-app

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away