项目实战
标记完成
<li v-for='todo in todos' :key='todo.id'>
<span v-bind:class="{completed: todo.completed}">{{ todo.title }}</span>
<input type="button" value="标为完成" @click="markAsCompleted(todo)"/>
...
methods: {
addTodo: function () {
...
this.todos.push({id: id++, title: this.newTodoTitle,
completed:false});
...
},
markAsCompleted: function (todo) {
todo.completed = true
},
},
功能05
<input v-if="!todo.completed" type="button" value="标为完成" @click="markAsCompleted(todo)"/>
功能06
<input v-if="!todo.completed" type="button"
value="标为完成" @click="markAsCompleted(todo)"/>
<input v-else type="button"
value="标为未完成" @click="markAsUnCompleted(todo)"/>
methods: {
...
markAsUnCompleted: function (todo) {
todo.completed = false
},
删除TODO
- 监听用户点击删除按钮的事件,绑定一个删除 todo 的方法,将当前需要删除的todo传给 vue
- this.todos.indexOf(todo) 用来定位元素的位置,然后删除掉这个位置的元splice(index, 1),1 表示只删除一个,即当前位置(index 的值)的元素
- 绑定删除事件
<li v-for='todo in todos' :key='todo.id'>
...
<input type="button" value="删除"
@click="removeTodo(todo)"/>
methods: {
...
removeTodo: function(todo){
index = this.todos.indexOf(todo)
this.todos.splice(index, 1)
}
功能07:友好删除
removeTodo: function(todo){
if(!confirm('确定删除?')){
return
}
...
功能08:撤销
...
data: function () {
return {
...
removedTodo: null,
...
methods: {
...
removeTodo: function(todo){
...
let pos = this.todos.indexOf(todo);
this.removedTodo = {
pos:pos,
todo:this.todos.splice(pos, 1)[0]
}
},
...
computed: {
...
hasRemovedTodo:function(){
return this.removedTodo != null
}
}
<input v-if="hasRemovedTodo" type="button" value="撤销" @click="restoreTodo()"/>
编辑和撤销
<li v-for='todo in todos' :key='todo.id'>
<span v-bind:class="{completed: todo.completed}"
v-on:dblclick="editTodo(todo)">{{ todo.title }}</span>
...
<input v-if="editedTodo !== null && editedTodo.id === todo.id"
type="text" value="编辑 todo..."
v-model="todo.title"
@keyup.enter="editDone(todo)"
@keyup.esc="cancelEdit(todo)"/>
data: function () {
return {
...
editedTodo: null,
...
methods: {
...
editTodo :function(todo){
this.editedTodo = {id: todo.id,
title: todo.title,
completed:todo.completed}
},
editDone:function(todo){
this.editedTodo = null
},
cancelEdit:function(todo){
todo.title = this.editedTodo.title;
this.editedTodo = null
}
功能09
editDone:function(todo){
if (todo.title === ''){
this.removeTodo(todo)
}
this.editedTodo = null
},
自定义指令
- 自定义指令提供如下几个钩子函数
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中) update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
- unbind:只调用一次,指令与元素解绑时调用
- 用户双击 todo 进入编辑状态后输入框自动获取焦点
- input 元素有一个 focus 方法可以来帮完成这个事情
- Vue 的自定义指令可以完成这个功能
- 指令是什么,就是用来指导被绑定的元素的行为,之前接触过 v-if、v-model、vbind 等指令
- 可以自己注册一个指令,然后实现某些钩子函数,从而指定被绑定元素的行为
- 实现一个 focus 指令,这个指令实现了 inserted 钩子函数,这个函数在被绑定的元素被插入 dom 时触发,且被绑定的元素会作为参数传入钩子函数,就可以在函数中对它操作
- 在 Vue 对象中声明局部指令
- 把它绑定到编辑框,这样编辑框出现时指令就被触发,从而聚焦
- 注意因为元素一旦出现一定要聚焦的,所以条件始终为 true
- vue对象中添加指令
var app = new Vue({
...
directives:{
focus:{
inserted: function(el){
el.focus()
}
}
}
<input v-if="editedTodo !== null && editedTodo.id === todo.id"
type="text" value="编辑 todo..."
v-focus="true"
...
全部标记完成
- 监听click事件
- 将所有未完成的todos标为完成
- markAllAsCompleted 里面用到一些 js 的高级方法,即 map 方法
- map 是一种函数式编程的思想
- 假设有一个列表,需要对列表中的每一个元素做同样的操作,直观的方法就是遍历列表,然后依次应用这个函数到每个元素上,最后把作用后的结果返回
- map 封装了这些步骤,让无需显示循环列表
- 在这里希望将 this.todos 这个列表中每一个完成的 todo 标为已完成,因此做了:
- his.todo.map(func)
- 这个 func 就是每一个 todo 的操作
- 即把所有未完成的 todo 的 todo.completed 置为 true
- 绑定事件
<div id="todo-app">
<input type="button" value="全部标记完成" @click="markAllAsCompleted()"/>
methods: {
...
markAllAsCompleted(){
this.todos.map(function(todo){
if(!todo.completed){
todo.completed = true
}
})
}
},
统计剩余未完成TODO
- 动态地根据实际未完成 todo 的数量来显示
- 计算 todos 列表中还有多少个 todo 的 completed 属性为 false,这些 todo 就是未完成的,得到这些 todo 的个数就可以
- 根据 Vue 对象已有的数据来计算新的结果,就是计算属性典型的应用场景
- l 来计算一下未完成 todo 的结果,然后在模板中引用它
- filter 函数
- filter 和之前讲过的 map 函数是类似的,都是函数式编程的思想
- map 用于将一个函数作用于列表的所有元素,然后得到一个作用后的列表结果
- filter 顾名思义,就是要根据某个检测函数去列表中筛选出符合检测要求的结果通常这个函数只返回两个值,列表元素符合要求返回真,否则返回假
- filter 会返回所有检测为真的元素组成的列表
- 这里的检测函数是:todo => !todo.completed
- 即如果 todo.completed 为假,即 todo 未完成,返回真,已完成返回假
- 绑定计算属性
<span>剩余 {{ leftTodoCount }} 项未完成 ---</span>
computed: {
...
leftTodoCount(){
return this.todos.filter(todo => !todo.completed).length
}