はじめに
Vue CLIを使って、シンプルなTodoを作成しながらVuejsを理解するサンプルが欲しくて作成しながらメモしたことを残しておきます。
前提として、以下の素晴らしい記事の内容を終えている前提で、以下の記事で紹介されているシンプルなTodoをVueCLIで作っていくという内容になります。
自分が色々試した結果上記記事がとてもわかりやすく最短であると感じました。
作成いただいた @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