基础案例:TodoMVC
学习目标:
- 掌握 Vue 中常用的实例选项
- 掌握 Vue 常用指令
案例介绍
需求说明
开始
下载模板
# 下载模板到本地,重命名为 todomvc-vue
# --depth=1 表示只下载最后一次的 commit,其它历史记录不要,这样可以提高下载速度
git clone https://github.com/tastejs/todomvc-app-template.git todomvc-vue --depth=1
# 切换到 todomvc-vue 目录中,安装依赖项
cd todomvc-vue
npm install
# 打开 todomvc-vue 中的 index.html 预览模板
任务列表
...
<template v-if="todos.length > 0">
<section class="main">
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-bind:checked="getToggleAllStatus()"
@change="handleToggleAll">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<li
v-for="(item, index) in todos"
v-bind:class="{completed: item.done}">
<div class="view">
<input class="toggle" type="checkbox" v-model="item.done">
<label>{{ item.title }}</label>
<button @click="handleRemoveTodo(index)" class="destroy"></button>
</div>
<input class="edit" value="Rule the web">
</li>
</ul>
</section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer class="footer">
<!-- This should be `0 items left` by default -->
<span class="todo-count"><strong>0</strong> item left</span>
<!-- Remove this if you don't implement routing -->
<ul class="filters">
<li>
<a class="selected" href="#/">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<!-- Hidden if no completed items are left ↓ -->
<button class="clear-completed">Clear completed</button>
</footer>
</template>
...
添加任务
...
<input
class="new-todo"
placeholder="What needs to be done?"
v-on:keyup.enter="handleAddTodo">
...
...
methods: {
...
handleAddTodo (e) {
const {target} = e // target 就是触发该事件的 DOM
const {value} = target
const {todos} = this
// 拿到数组最后一个元素的 id + 1 就可以得到一个唯一不重复的 id
// 当数组是空的时候根本就没有最后一项,所以 todos[todos.length - 1] 的结果就是 undefined
// undefined.id 不就报错了吗?
const lastTodo = todos[todos.length - 1]
// 如果有最后一个元素,则让该元素.id + 1,否则默认给个 1
const id = lastTodo ? lastTodo.id + 1 : 1
if (value.trim().length !== 0) {
this.todos.push({
id, // 当 key 和 value 名字一样的时候,可以简写, id 等价于 id: id
title: value,
done: false
})
// 操作 DOM 清空文本框
target.value = ''
}
},
...
}
...
切换所有任务的完成状态
...
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-bind:checked="getToggleAllStatus()"
@change="handleToggleAll">
...
...
methods: {
...
handleToggleAll (e) {
const checked = e.target.checked
this.todos.forEach((item) => {
item.done = checked
})
},
getToggleAllStatus () {
let status = true
this.todos.forEach(item => {
if (item.done === false) {
status = false
}
})
return status
},
...
}
...
删除单个任务
...
<button @click="handleRemoveTodo(index)" class="destroy"></button>
...
...
methods: {
...
handleRemoveTodo (delIndex) {
this.todos.splice(delIndex, 1)
},
...
}
...
删除所有已完成任务
...
<button
class="clear-completed"
@click="handleClearAllDone">Clear completed</button>
...
...
methods: {
...
handleClearAllDone () {
for (let i = 0; i < this.todos.length; i++) {
const item = this.todos[i]
if (item.done === true) {
this.todos.splice(i, 1)
i-- // 在遍历过程中删除元素之后,让索引减一次,防止有漏网之鱼
}
}
},
...
}
...
显示所有剩余未完成任务数
方法方式:
...
<span class="todo-count"><strong>{{ getRemaining() }}</strong> item left</span>
...
...
methods: {
...
getRemaining () {
let count = 0
this.todos.forEach(item => {
if (item.done === false) {
count++
}
})
return count
}
...
}
...
计算属性方法:
...
<strong>{{ remaining }}</strong> item left</span>
...
...
computed: {
...
remaining () {
let count = 0
this.todos.forEach(item => {
if (item.done === false) {
count++
}
})
return count
}
...
}
...
持久化存储
...
new Vue({
...
data: {
...
todos: JSON.parse(window.localStorage.getItem('todos') || '[]')
...
},
...
watch: {
...
todos: {
handler () { // 固定的 handler ,当 todos 发生改变会自动调用 handler 方法
// 本地存储只能存储字符串,所以这里要把数组转成字符串再存储
window.localStorage.setItem('todos', JSON.stringify(this.todos))
},
deep: true // deep 配置为 true 表示深度监视
}
...
},
...
})
...