Vue.jsの公式チュートリアル、ずいぶん充実しているなぁ。
だけど、一通り終わっちゃったし、実務で使うまでにもういくつか練習してみたいな。
ということで、こちらのページで紹介されているチュートリアル「ToDoリストを作りながら学習しよう!」をベースに、ToDoリスト作ってみました。
https://cr-vue.mio3io.com/tutorials/todo.html
変更した点
routerを使った
元サイトではindex.html、main.css、main.jsだけで実装していますが、せっかくの練習なので、vue-routerをつかいコンポーネントを外部から読み込んでくる形にしました(1ページだから意味ないけど)。以下構成です。
- App.vue
- main.js
- router
└ index.js - views
└ Top.vue
ローカルストレージをそのまま使いました
ローカルストレージAPIから抜き出してくるのではなく、こちらに書いてある方法で直接ローカルストレージに読み書きしました。
https://jp.vuejs.org/v2/cookbook/client-side-storage.html
完成図
cssは上記サイトからコピペさせていただきましたm(__)m
コード
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
import Vue from 'vue'
import App from './App.vue'
import router from './router/'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
mode : 'history',
base : process.env.BASE_URL,
routes: [
{
path: '/',
name: 'top',
component: () => import('../views/Top.vue')
}
]
})
export default router
<template>
<div class="top">
<h2>TODOリスト</h2>
<label v-for="(option, key, index) in options" :key="index">
<input type="radio"
v-model="current"
v-bind:value="option.value" />{{ option.label }}
</label>
<span>{{ computedTodos.length }} 件を表示中</span>
<table>
<thead>
<tr>
<th class="id">ID</th>
<th class="comment">コメント</th>
<th class="state">状態</th>
<th class="button">-</th>
</tr>
</thead>
<tbody>
<tr v-for="item in computedTodos" v-bind:key="item.id">
<th>{{ item.id }}</th>
<td>{{ item.comment }}</td>
<td class="state">
<button @click="doChangeState(item)">{{ labels[item.state] }} </button>
</td>
<td class="button">
<button @click.ctrl="doRemove(item)">削除</button>
</td>
</tr>
</tbody>
</table>
<p>※削除ボタンはコントロールキーを押しながらクリックしてください</p>
<h2>新しい作業の追加</h2>
<form @submit.prevent="doAdd" class="add-form">
<p>
<span>コメント</span>
<input type="text" ref="comment">
<button type="submit">追加</button>
</p>
</form>
</div>
</template>
<script>
export default{
name: 'top',
data(){
return {
todos: [],
options: [
{ value: -1, label: 'すべて' },
{ value: 0, label: '作業中' },
{ value: 1, label: '完了' }
],
current: -1,
uid: 0
}
},
computed: {
labels(){
return this.options.reduce(function(a,b){
return Object.assign(a, { [b.value]: b.label })
}, {})
},
computedTodos: function(){
return this.todos.filter(function(el) {
return this.current < 0 ? true: this.current === el.state
}, this)
}
},
created(){
if(localStorage.getItem('todos')){
try{
this.todos = JSON.parse(localStorage.getItem('todos'))
} catch(e){
localStorage.removeItem('todos')
}
}
if(localStorage.getItem('uid')){
this.uid = localStorage.getItem('uid')
}
},
methods:{
doAdd : function(){
var comment = this.$refs.comment
if(!comment.value.length){
return
}
this.uid += 1
this.todos.push({
id: this.uid,
comment: comment.value,
state: 0
})
localStorage.setItem('uid',this.uid)
comment.value = ''
},
doChangeState: function(item){
item.state = item.state ? 0 : 1
},
doRemove: function(item){
var index = this.todos.indexOf(item)
this.todos.splice(index,1)
}
},
watch: {
todos: {
handler: function(todos) {
localStorage.setItem('todos',JSON.stringify(todos))
},
deep: true
}
}
}
</script>
<style>
省略
</style>
v-forでキー指定
<label v-for="(option, key, index) in options" :key="index">
<input type="radio"
v-model="current"
v-bind:value="option.value" />{{ option.label }}
</label>
上記みたくキーを指定してあげないと下記みたく怒られたので、キーを指定しました。
5:5 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
✖ 1 problem (1 error, 0 warnings)
clickを省略記法に変えました
<td class="state">
<button @click="doChangeState(item)">{{ labels[item.state] }} </button>
</td>
<td class="button">
<button @click.ctrl="doRemove(item)">削除</button>
</td>
Vue.jsでは"v-on:click"を"@click"のように省略して書けるので省略しました。
ローカルストレージへの読み書き
created(){
if(localStorage.getItem('todos')){
try{
this.todos = JSON.parse(localStorage.getItem('todos'))
} catch(e){
localStorage.removeItem('todos')
}
}
}
こちらを参考にしてローカルストレージへの読み書きを直接する方法に変えました。
https://jp.vuejs.org/v2/cookbook/client-side-storage.html
doAdd : function(){
var comment = this.$refs.comment
if(!comment.value.length){
return
}
this.uid += 1
this.todos.push({
id: this.uid,
comment: comment.value,
state: 0
})
localStorage.setItem('uid',this.uid)
comment.value = ''
}
IDの更新は、uidという変数をローカルストレージとVueとで共有して更新していくやり方にしました。
watch: {
todos: {
handler: function(todos) {
localStorage.setItem('todos',JSON.stringify(todos))
},
deep: true
}
}
一瞬詰まったのが、ローカルストレージへのオブジェクトの保存。
ローカルストレージには配列やオブジェクトなど複雑なものは入れられないので、Stringに変換する必要があります。
シンプルで取り組みやすいチュートリアルをありがとうございました!
コンポーネント化とかvue-routerとかもっと触ってみたいので、次は複数ページにわたるアプリを作ってみたいと思います!