1、 综合案例: TodoMVC
TodoMVC 是一个经典项目,让开发者快速实践到框架开发方式
官网: http://todomvc.com/
评价: 功能完备不冗余,多样实现引深思
2、准备工作
从 github 克隆项目模板
git clone https://github.com/tastejs/todomvc-app-template.git
进入项目目录,安装项目依赖
cd 项目目录
npm install
安装 Vue.js
npm install vue
3、需求分析
事项列表展示:有事项的情况;没有事项的情况
状态栏展示:个数展示;单位处理
事项状态切换:单个事项切换;多个事项切换
事项新增:内容检测
事项删除:单个事项删除;已完成事项删除
事项编辑:触发编辑;取消编辑;保存编辑
事项筛选:点击切换显示类别;更新渲染所有事项
事项数据持久化:读取本地存储;更新本地存储
4、事项列表展示-实现
引入 Vue.js 文件,创建 Vue 实例设置挂载元素
在 data 中设置 todos 存储初始数据
data: {
todos: [ // todos 用于存储所有事项信息
{ id: 1, title: '示例内容1', completed: false },
{ id: 2, title: '示例内容2', completed: true },
{ id: 3, title: '示例内容3', completed: true },
]
}
设置事项视图:
<li v-for="todo in todos" :key="todo.id" :class="{completed:todo.completed}">
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed">
<label>{{ todo.title }}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Rule the web">
</li>
设置有无事项时的显示状态:
<section class="main" v-show="todos.length"></section>
<footer class="footer" v-show="todos.length"></footer>
5、状态栏信息展示
需要实现的功能为:
个数展示:
computed: {
remaining () {
return this.todos.filter(function (todo) {
return !todo.completed;
}).length;
}
}
单位处理:
methods: {
pluralize: function (word) {
return word + (this.remaining === 1 ? '' : 's');
}
},
6、事项状态切换
单个事项切换:
通过 v-mmodel 的设置已经实现了,体会双向数据绑定的好处
多个事项切换:
单个事项操作:单个事项切换会导致 toggle-all 状态变化,我们可以通过 ~ 来进行判断
computed: {
...
allDone () {
return this.remaining === 0;
}
}
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="allDone">
全部切换选择框操作:设置 v-model 后,主动操作 toggle-all 相当于设置 allDone 数据,这时需要给 allDone 设置 setter来处理
allDone: {
get () {
return this.remaining === 0;
},
set (value) {
this.todos.forEach(function (todo) {
todo.completed = value;
})
}
}
7、事项新增
输入框内容绑定: 在 data 中设置 newTodo 用于存储数据,并绑定给新增输入框
data: {
newTodo: ''
}
<input class="new-todo" placeholder="需要做点啥?" autofocus v-model="newTodo">
回车新增事项: 输入框回车时检测内容,并根据输入内容新增事项到 todos
methods: {
addTodo () {
var value = this.newTodo.trim();
if (!value) {
return;
}
this.todos.push({id: this.todos.length, title: value, completed: false});
this.newTodo = '';
}
}
<input class="new-todo" placeholder="需要做点啥?" autofocus v-model="newTodo" @keyup.enter="addTodo">
8、事项删除
单个事项删除: 点击单个事项中的删除按钮时,删除 todos 中对应的对象数据
removeTodo (todo) {
// console.log(this.todos.indexOf(todo));
var index = this.todos.indexOf(todo)
this.todos.splice(index, 1);
}
已完成事项删除: 已完成事项按钮需要在具有已完成事项时显示;操作后,事项列表只保留未完成事项即可
<button class="clear-completed" v-show="remaining < todos.length">清除已完成事项</button>
clearTodo () {
var complete = this.todos.filter((todo) => !todo.completed);
this.todos = complete;
}
9、事项编辑
触发编辑
双击时进行记录正在编辑的 todo ,并保存原始 todo 内容
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
editTodo (todo) {
this.editingTodo = todo;
this.todoTitle = todo.title;
}
自动获取焦点: 触发编辑后,输入框无法自动获取焦点,可通过自定义指令实现
directives: {
"todo-focus"(el) {
el.focus();
}
}
<input class="edit" v-model="todo.title" v-todo-focus="todo === editingTodo"</li>
正在被编辑的 li 需要设置类名 editing
<li v-for="todo in todos" :key="todo.id" :class="{completed: todo.completed, editing: todo === editingTodo}">
取消编辑: 点击 esc 取消编辑,还原事项内容与状态
// 取消编辑
cancelEdit (todo) {
this.editingTodo = null;
todo.title = this.todoTitle;
},
保存编辑: 点击回车键或失去焦点时保存编辑
enterEdit (todo) {
this.editingTodo = null;
todo.title = todo.title.trim();
if (!todo.title) this.removeTodo(todo);
}
回车也会触发失去焦点,为避免重复触发,需要进行检测(我没遇到这种情况)
10、事项筛选
记录筛选类别: 在 data 中声明数据存储当前显示的事项类别,并在点击筛选按钮时更改显示的事项类别
data: {todoType: 'all'}
<a href="javascript:;" :class="{selected : todoType === 'all'}" @click="todoType = 'all'">All</a>
点击更改类别
设置用于筛选不同类别事项的函数,并统一储存
et filters = {
all(todos) {
return todos;
},
active(todos) {
return todos.filter((todo) => !todo.completed);
},
complete(todos) {
return todos.filter((todo) => todo.completed);
}
}
设置计算属性处理 TodoType ,并设置给视图
filterTodo() {
return filters[this.todoType](this.todos);
},
<li v-for="todo in filterTodo" ...>
之前使用过的数据筛选函数也可以通过 filters 进行统一设置
remaining() {return filters.active(this.todos).length;}
11、事项数据持久化
获取本地存储:
封装函数,用于进行本地存储数据读取;
将事项数据更改为本地存储数据;
更新本地存储
封装本地存储的更新功能;
由于多种事项操作都需要更新本地存储,单个设置十分繁琐,可以通过侦听器统一设置
localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,localStorage只支持string类型的存储
使用 localStorage 创建一个本地存储的 name/value 对
// 声明一个常量键;用于存储 window 下的 localStorage.getItem / localStorage.setItem 操作的键 (如果要操作同一个数据的时候,需要键)
// TODOS_KEY 是键名字 ; todos_vue 表示:通过 vue.js 实现的一个用来事项操作的功能
const TODOS_KEY = "todos_vue";
let todoStorage = {
get () {
// JSON.parse() 转换成 json 数据格式
return JSON.parse(localStorage.getItem(TODOS_KEY)) || [];
},
set (todos) {
// setItem(键名, 设置的数据的数据)
localStorage.setItem(TODOS_KEY, JSON.stringify(todos));
}
}
data:{
// 将 todos 设置为本地存储的数据
todos: todoStorage.get()
},
watch: {
// 监听对象的名字
todos: {
deep: true,
handler: todoStorage.set
}
},