vue之TodoMVC项目实战
一、初始化项目
1、下载模板
进入github中https://github.com/tastejs/todomvc-app-template,并且在命令行将其clone下来
git clone https://github.com/tastejs/todomvc-app-template.git
2、安装依赖
进入项目目录中安装依赖
npm install
3、引入vue.js文件
首先在命令行中安装vue
npm install vue
然后再index.html中引入
然后再app.js文件中写入相应的逻辑代码
二、实现功能
1、数据列表渲染功能
1.1 功能分析
- 有数据
每一个数据对象:
{
id:1,
content:'',
complated:'' #表示是否已经完成的任务true(false) }
并且每一个数据对象有三个状态:
未完成(没有样式)
已完成(.completed )
编辑中( .editing )
- 无数据
输入框下面的部分应该隐藏起来
1.2 实现
- 创建一个数据源
items:[
{id:1,content:'dddd',completed:false},
{id:2,content:'aaaa',completed:false},
{id:3,content:'bbbb',completed:false},
{id:4,content:'cccc',completed:false},
]
- 处理有数据的情况
<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 items" :class="{completed:item.completed}">
<div class="view">
<!-- v-model进行双向绑定,checkbox是否选中 -->
<input class="toggle" type="checkbox" v-model="item.completed">
<!-- 获取对应对象的内容 -->
<label>{{item.content}}</label>
<!-- 将id传入用于删除对应的数据 -->
<button class="destroy" :value="item.id"></button>
</div>
<input class="edit" value="Create a TodoMVC template">
</li> </ul>
- 处理无数据的情况
利用v-show指令判断数组长度是否为0,也就是是否为false
<footer class="footer" v-show="items.length">
<!-- 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>
2、添加任务功能
2.1 功能分析
- 将输入的内容添加到任务列表中
- 如果输入为空,不做任何事情
- 按enter键添加到任务列表,并清空输入框
2.2 实现
<header class="header">
<h1>todoapp</h1>
<!--绑定键盘事件添加数据-->
<input @keyup.enter="addItem" class="new-todo" placeholder="What needs to be done?" autofocus>
</header>
在app.js文件的methods参数写入方法
addItem(event){
//获取文本框中的值
const newValue=event.target.value.trim();
//判断是否为空,如果为空什么也不做
if(!newValue.length){
return
}
//如果不为空将新值添加到数组中
newObject={
id:this.items.length+1, //生成一个新的id
content:newValue,
completed:false
};
this.items.push(newObject);
//将文本框置空
event.target.value=''
}
3、显示所有未完成任务数功能
3.1 功能分析
- 当数组发生变化时计算内部对象的个数,可通过计算属性
- 利用filter函数筛选出未完成任务的个数
- 任务数量为单数时为item,为复数时为items
3.2 实现
<!-- 返回所有未完成任务的数量,并且如果为单数就为item,否则为items -->
<span class="todo-count"><strong>{{ incomplete }}</strong> item{{ incomplete===1? '' : 's' }} left</span>
在app.js文件的computed参数中写入对应的方法
incomplete(){
//箭头函数返回未完成任务的个数
return this.items.filter(item=>!item.completed).length
// this.items.filter(function (item) {
// return !item.completed
// }).length
}
4、切换所有任务状态
4.1 功能分析
- 点击输入框前面的复选框后,将所有任务标记为与复选框相同的状态
(1)使用计算属性中的set方法,此时需要v-model进行数据的双向绑定,通过监听数据属性,获取新的checkbox的值
(2)将获取的值赋给每一个任务项
- 当 选中/取消 某个任务后,复选框 也应同步更新状态
(1)使用计算属性的get方法,判断所有incomplete是否为 0 ,
(2)绑定了 incomplete,当 incomplete发生变化后, 自动更新复选框状态(如果为0说明任务已经全部完成,复选框会自动选中,反之不选中
4.2 实现
index.html
<input id="toggle-all" v-model="isSelectAll" class="toggle-all" type="checkbox">
app.js
isSelectAll:{
//循环数据源中的每一个对象,并且将通过v-model双向绑定获取的值赋给每一个item中的状态,从而根据input checkbox的状态去顶任务的状态
set:function (newState) {
this.items.forEach(function (item) {
item.completed=newState;
})
}, //根据任务完成的状态完成绑定v-model的input checkbox框的状态获取
get:function () { return this.incomplete===0
} }
5、删除任务项
5.1 功能分析
- 悬停在某个任务项上显示 X 移除按钮,可点击移除当前任务项
(1) 移除按钮处添加点击事件
(2)通过数组函数 splice 移除任务
5.2 实现
index.html
<button class="destroy" :value="item.id" @click="removeItem(index)"></button>
app.js
//移除对象 splice(),传入移除对象的索引,以及从此处开始完后删掉的数量
removeItem(index){
this.items.splice(index,1) },
6、编辑任务项
6.1 功能分析
- 双击 <label> (某个任务项)进入编辑状态(在 <li> 上通过 .editing 进行切换状态)
- 进入编辑状态后输入框显示原内容,并会自动获取编辑焦点
- 输入状态按 Esc 取消编辑,editing 样式应该被移除
- 按 Enter 键 或 失去焦点时 保存改变数据,移除 editing 样式
6.2 实现
- 双击 <label> (某个任务项)进入编辑状态(在 <li> 上通过 .editing 进行切换状态)
<!-- 获取对应对象的内容,在内容的标签上绑定双击事件-->
<label @dblclick="toEdit(item)">{{item.content}}</label>
//双击进入编辑模式,也就是加入.editing样式
toEdit(item){
this.currentItem=item
},
- 进入编辑状态后输入框显示原内容,并会自动获取编辑焦点
<!-- 显示点击编辑后的默认值:value="item.content" -->
<input class="edit" v-todo-focus="item===currentItem" :value="item.content" >
//自定义局部指令,用于聚焦编辑框修改内容,当进入编辑模式的对象与传入的对象是同一个时聚焦,防止聚焦到别处
directives:{
"todo-focus":{
//当指令的值更新后会调用此方法
update(el,binding){
//el表示作用的元素
//binding表示指令后输入的内容
if(binding.value){
el.focus()
} } }
},
- 输入状态按 Esc 取消编辑,editing 样式应该被移除
<!-- 显示点击编辑后的默认值:value="item.content" -->
<input class="edit" @keyup.esc="cancelEdit"
v-todo-focus="item===currentItem"
:value="item.content" >
//点击键盘的esc取消编辑
cancelEdit(){
this.currentItem=null
},
- 按 Enter 键 或 失去焦点时 保存改变数据,移除 editing 样式
<!-- 显示点击编辑后的默认值:value="item.content" -->
<input class="edit" @keyup.esc="cancelEdit"
@keyup.enter="saveData(item,index,$event)"
@blur="saveData(item,index,$event)"
v-todo-focus="item===currentItem"
:value="item.content" >
//通过enter以及blur事件,保存数据,只有当获取焦点才会触发该事件
saveData(item,index,event){
//获取对应文本框中去除空格后的内容
const content=event.target.value.trim();
//判断内容是否为空,如果为空,删除任务项
if(!content){
//重用removeItem函数删除
this.removeItem(index)
}
//否则对数据进行更新
item.content=content;
//更新后移除编辑样式,.editing
this.currentItem=null },
7、清除所有任务项
7.1 功能分析
- 单击右下角 Clear completed 按钮时,移除所有已完成任务
- 当列表中没有已完成的任务时,应该隐藏 Clear completed 按钮
7.2 实现
- 单击右下角 Clear completed 按钮时,移除所有已完成任务
在index.html添加点击事件,然后再app.js中通过filter函数锅炉出所有未完成任务,并且赋给items
index.html
<!-- Hidden if no completed items are left ↓ -->
<!--在对应的地方添加点击事件-->
<button @click="removeAllCompleted" class="clear-completed">Clear completed</button>
app.js
//过滤出所有未完成的任务项,并且将过滤后的数据赋值给items
removeAllCompleted(){
this.items= this.items.filter((item)=>!item.completed)
},
- 当列表中没有已完成的任务时,应该隐藏 Clear completed 按钮
判断总的任务数与没有完成任务数的大小,如果当总任务数 ( items.length ) > 未完成数 ( incomplete) ,说明列表中还有已完成数据,则是显示按钮;反之不显示。
index.html
<button @click="removeAllCompleted" class="clear-completed" v-show="items.length > incomplete">Clear completed</button>
app.js
//计算属性
incomplete(){
//箭头函数返回未完成任务的个数
return this.items.filter(item=>!item.completed).length
// this.items.filter(function (item) {
// return !item.completed
// }).length
},
8、 过滤出不同状态 的数据
8.1 功能分析
- 根据点击的状态不同,获取不同状态下的数据
- 改变不同状态下的样式
8.2 实现
- 根据点击的状态不同,获取不同状态下的数据
(1)在 data 中定义接收状态变化的值filterStatus
(2)通过 window.onhashchange 获取点击的路由 hash (# 开头的),来获取对应的那个状态值,并将状态值赋值给 filterStatus
(3)定义一个计算属性 filterItems 用于过滤出目标数据, 用于感知 filterStatus 的状态值变化,当变化后,通过 switch-case + filter 过滤出目标数据。
app.js
//1、定义变量
data:{
filterState:'all', }, //2、获取路由hash值,并且截取需要的路由,当截取的为空时返回‘all’
window.onhashchange=function () {
// window.location.hash 获取的是这样的数据 #/active
const hash=window.location.hash.substr(2) || 'all';
//将状态值赋值给vm实例中的filterState
vm.filterState = hash
}; //第一次访问生效,手动调用一次
window.onhashchange() //3、定义计算属性filterItems
//过滤出不同状态下的数据,以this.filterState为过滤条件
filterItems(){
switch (this.filterState) {
case "active":
return this.items.filter(item=>!item.completed);
break
case "completed":
return this.items.filter(item=>item.completed);
break
default:
return this.items;
break
} },
index.html
<!--将v-for循环的items替换为filterItems-->
<li v-for="(item,index) in filterItems" :class="{completed:item.completed,editing:item===currentItem}">
- 改变不同状态下的样式
<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>
将上述被选中的样式切换为:
class="selected"
如下:
<ul class="filters">
<li>
<a :class="{selected:filterState === 'all'}" href="#/">All</a>
</li>
<li>
<a :class="{selected:filterState === 'active'}" href="#/active">Active</a>
</li>
<li>
<a :class="{selected:filterState === 'completed'}" href="#/completed">Completed</a>
</li>
</ul>
9、数据持久化(localStorage)
9.1 功能分析
目前数据只是单纯的放在内存中,自己定义的数组:
data:{
items:[
{id:1,content:'dddd',completed:false},
{id:2,content:'aaaa',completed:false},
{id:3,content:'bbbb',completed:false},
{id:4,content:'cccc',completed:false},
],
currentItem:null,
filterState:'all', },
如果需要保存在本地,可以使用localStorage ,它主要是用于本地存储数据。语法如下:
//保存数据语法:
localStorage.setItem("key", "value"); //读取数据语法:
var data= localStorage.getItem("key"); //删除数据语法:
localStorage.removeItem("key");
本项目中使用的步骤如下:
- 定义 itemStorage 数据存储对象,内部自定义 fetch 获取本地数据 ,save 存数据到本地。
- 修改 Vue 实例中 data 选项的 items 属性,通过 itemStorage.fetch() 方法初始化数据
- Vue 实例中增加一个 watch 选项,用于监听 items 的变化,一旦变化通过 itemStorage.save() 重新保存数据到本地
9.2 实现
- 定义 itemStorage 数据存储对象,里面自定义 fetch 获取本地数据 ,save 存数据到本地。
var STOREGE_KEY = "todo-items"; //定义localstorege对象,注意是在Vue实例外面定义的
const itemStorage = {
//获取本地数据的方法
fetch:function () {
//获取数据并且数据反序列化,变成数组对象,如果为空,则是空数组
return JSON.parse(localStorage.getItem(STOREGE_KEY) || '[]')
},
//保存数据到本地,items就是需要保存的数据源,并且以JSON字符串的格式存储
save:function (items) {
localStorage.setItem(STOREGE_KEY,JSON.stringify(items))
} };
- 修改 Vue 实例中 data 选项的 items 属性,通过 itemStorage.fetch() 方法初始化数据
var vm = new Vue({
el:'#todoapp',
data:{
// items:[
// {id:1,content:'dddd',completed:false},
// {id:2,content:'aaaa',completed:false},
// {id:3,content:'bbbb',completed:false},
// {id:4,content:'cccc',completed:false},
// ],
//从本地获取数据
items:itemStorage.fetch(), currentItem:null,
filterState:'all', },
- Vue 实例中增加一个 watch 选项,用于监听 items 的变化,一旦变化通过 itemStorage.save() 重新保存数据到本地
//监听器,用于本地化数据的存储,一旦数组对象有变化,立即存储
watch:{
//监听items,一旦items发生变化就会执行
items:{
deep:true,//需要监听数组对象内部的变化,需要指定deep:true
handler(newitems,olditems){
// newitems:新的数组对象
// olditems:之前的数组对象
itemStorage.save(newitems)
}
}
},
项目地址:https://github.com/ShenJianPing0307/todo-demo
vue之TodoMVC项目实战的更多相关文章
- vue.js的项目实战
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由蔡述雄发表于云+社区专栏 需求背景 组件库是做UI和前端日常需求中经常用到的,把一个按钮,导航,列表之类的元素封装起来,方便日常使用, ...
- vue.js+koa2项目实战(五)axios 及 vue2.0 子组件和父组件之间的传值
axios 用法: 1.安装 npm install axios --save-dev 2.导入 import axios from 'axios'; 3.使用 axios.post(url,para ...
- vue.js+koa2项目实战(四)搭建koa2服务端
搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...
- vue.js+koa2项目实战(一)创建项目和elementUI配置
前端采用vuex+element-ui: 后端采用koa2+restfulAPI+sequlize: (一)项目介绍 宠物社区 1.社区 2.好友 3.说说 4.宠粮 5.健康 (二)项目框架 1.V ...
- vue.js及项目实战[笔记]— 03 vue.js插件
一. vue补充 1. 获取DOM元素 救命稻草,document.querySelector 在template中标示元素`ref = "xxx" 在要获取的时候,this.$r ...
- vue.js及项目实战[笔记]— 02 vue.js基础
一. 基础 1. 注册全局组件 应用场景:多出使用的公共性能组件,就可以注册成全局组件,减少冗余代码 全局APIVue.component('组件名','组件对象') 2.附加功能:过滤器&监 ...
- vue.js及项目实战[笔记]— 01 vue.js
一. vue基础 1. 历史介绍 angular 09年,年份较早,一开始大家是拒绝的 react 2013年,用户体验较好,直接拉到一堆粉丝 vue 2014年,用户体验较好 前端框架与库的区别 j ...
- vue.js+koa2项目实战(三)登录注册模态框
登录注册模态框 注: [Vue warn]: Do not use built-in or reserved HTML elements as component id: diaLog 原因:diaL ...
- vue.js+koa2项目实战(二)创建 HeadBar 组件
elementUI界面布局 1.创建 HeadBar 组件 HeadBar.vue <template> <el-row> <el-col :span="2&q ...
随机推荐
- python图像特征提取
这里使用的是python 3.5 .opencv_python-3.4.0+contrib,特征提取的代码如下: import cv2 img = cv2.imread("feature.j ...
- python之将Unicode文本标准化
在需要比较字符串的程序中使用字符的多种表示会产生问题. 为了修正这个问题,你可以使用unicodedata模块先将文本标准化: s1 = 'Spicy Jalape\u00f1o' s2 = 'Spi ...
- MySQL中orderby和limit分页数据重复的问题
背景 读取规则是按照某表中sequence字段排序的,而这个字段是让人手工填写的.那么,可想而知,数据一多,难免会出现填写的值相同的情况. 综上所述,可能就会导致以下两条sql出现数据重叠的情况: s ...
- Vue项目引入sass
最近两天手头的事情暂时搞完了,可以抽出空来学习一下东西,之前项目都是鹏哥搭建好了,我们在直接在里面写代码,sass语法用来写样式还是比较方便常用的,今天就来试试怎么引入和配置sass 参考文章:Vue ...
- 事件循环--eventloop
一.什么是事件循环? 事件循环是 JS 实现异步的具体解决方案,同步代码直接执行,异步函数或代码块先放在异步队列中,待同步函数执行完毕,轮询执行异步队列的函数. 事件循环 二.node.js中的事件循 ...
- 【记录】原生js日期格式化转换方法
情况一:将日期转换为指定的格式:比如转换成 年月日时分秒 首先我们在js中定义函数如下 Date.prototype.format = function(fmt) { var o = { " ...
- python3 获取当前路径及os.path.dirname的使用
方法一: import sys,os os.getcwd()#然后就可以看见结果了 方法二: import os os.path.dirname(os.path.realpath('__file__' ...
- Application.mk语法解释(转)
转自:http://blog.csdn.net/roland_sun/article/details/46318893 Application.mk是用来描述你的应用程序需要哪些模块,以及这些模块所要 ...
- mongoose 数据库连接
1安装mongoose npm install mongoose 安装成功 2.打开数据库 mongod --path E:\mongo 成功 创建一个db.js var mongoose = req ...
- spring 转换器和格式化
Spring总是试图用默认的语言区域将日期输入绑定 到java.util.Date.假如想让Spring使用不同的日期样 式,就需要用一个Converter(转换器)或者 Formatter(格式化) ...