一、初始化项目
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 功能分析
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 功能分析
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 功能分析
(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 功能分析
6.2 实现
<!-- 获取对应对象的内容,在内容的标签上绑定双击事件-->
<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() } } } },
<!-- 显示点击编辑后的默认值:value="item.content" --> <input class="edit" @keyup.esc="cancelEdit" v-todo-focus="item===currentItem" :value="item.content" >
//点击键盘的esc取消编辑 cancelEdit(){ this.currentItem=null },
<!-- 显示点击编辑后的默认值: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 功能分析
7.2 实现
在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) },
判断总的任务数与没有完成任务数的大小,如果当总任务数 ( 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");
本项目中使用的步骤如下:
9.2 实现
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)) } };
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‘, },
//监听器,用于本地化数据的存储,一旦数组对象有变化,立即存储 watch:{ //监听items,一旦items发生变化就会执行 items:{ deep:true,//需要监听数组对象内部的变化,需要指定deep:true handler(newitems,olditems){ // newitems:新的数组对象 // olditems:之前的数组对象 itemStorage.save(newitems) } } },
项目地址:https://github.com/ShenJianPing0307/todo-demo
原文:https://www.cnblogs.com/shenjianping/p/11271828.html