项目结构
1 参考todomvs,网站:http://todomvc.com/
2 模板仓库地址:https://github.com/tastejs/todomvc-app-template.git
3 git拉取:git clone https://github.com/tastejs/todomvc-app-template.git
4 拉取下来文件如图
.git
git版本管理器css
app.css样式js
app.js书写效果.editorconfig
编辑器设置.gitattributes
git的设置.gitignore
git管理忽略的文件的配置.app-readme.md
可删除index.html
html主体.package.json
项目描述;使用命令行:npm i 下载项目依赖包readme.md
上传git展示的文档
项目功能
1 展开事项列表
2 添加事项
3 编辑事项
4 删除事项
5 切换单条事项状态
6 批量切换事项状态
7 清除已完成事项
8 同步未完成事项总数
9 显示/隐藏清除已完成按钮
10 切换不同事项的显示
11 数据同步到本地存储
实现效果
完整代码
一、HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Template • TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
</head>
<body>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<!-- 变化1 -->
<!--
v-model.trim:实时获取去除前后空格的文本框输入的值;
@keyup.enter:按下回车时执行add方法
-->
<input class="new-todo" placeholder="What needs to be done?"
autofocus
v-model.trim="newTask"
@keyup.enter="add"
>
</header>
<section class="main">
<input id="toggle-all" class="toggle-all" type="checkbox">
<!-- 变化2 -->
<!--
@click:绑定点击事件,当点击时执行toggleAll函数;
v-show:当Shown值为true时让其显示,反之隐藏
-->
<label for="toggle-all" @click="toggleAll" v-show="Shown">Mark all as complete</label>
<ul class="todo-list">
<!-- 变化3 -->
<!-- 类名:completed改变事项的状态为已完成;类名:editing让文本框进入编辑状态-->
<!--
v-for:遍历数组tasks;
:class:当task.completed传回的值为true时添加类名completed,当isEditing==task.id时添加类名editing
v-if:获取completed状态
-->
<li v-for="task in tasks"
:class="{completed:task.completed,editing:isEditing==task.id}"
v-if="show(task.completed)"
>
<div class="view">
<!-- 变化4 -->
<!-- v-model:实时获取task.completed的值 -->
<input class="toggle" type="checkbox" v-model="task.completed">
<!-- 变化5 -->
<!--
@dblclick:双击isEditing=task.id的文本框,也就是让当前文本框进入编辑状态;
v-text:更新task.title
-->
<label
@dblclick="isEditing=task.id"
v-text="task.title"
></label>
<!-- 变化6 -->
<!-- @click:点击删除按钮时判断是否是当前的事项,是就删除 -->
<button class="destroy" @click="remove(task.id)"></button>
</div>
<!-- 变化7 -->
<!--
v-todo-focus:如果isEditing==task.id为true,就让input自动聚焦;
v-model:更新task.title;
@keyup.enter:当按下回车键时让isEditing=-1;
@blur:当焦点离开文本框时,让isEditing=-1
-->
<input class="edit"
v-model="task.title"
@keyup.enter="isEditing=-1"
@blur="isEditing=-1"
v-todo-focus="isEditing==task.id"
>
</li>
</ul>
</section>
<!-- 变化8 -->
<!-- v-show:当Shown值为true时让其显示,反之隐藏 -->
<footer class="footer" v-show="Shown">
<span class="todo-count"><strong v-text="activeNum"></strong> item left</span>
<ul class="filters">
<li>
<!-- 变化9 -->
<!-- :class:当flag的路由全等于''时,添加类名selected -->
<a :class="{selected:flag===''}" href="#/">All</a>
</li>
<li>
<!-- 变化10 -->
<!-- :class:当flag.completed全等于false时,添加类名selected -->
<a :class="{selected:flag.completed===false}" href="#/active">Active</a>
</li>
<li>
<!-- 变化11 -->
<!-- :class:当flag.completed全等于true时,添加类名selected -->
<a :class="{selected:flag.completed===true}" href="#/completed">Completed</a>
</li>
</ul>
<!-- 变化12 -->
<!--
@click:点击清除按钮时执行函数clearAll;
v-if:当有已完成事项时,返回true让其显示
-->
<button class="clear-completed" @click="clearAll" v-if="isShow">Clear completed</button>
</footer>
</section>
<script src="node_modules/todomvc-common/base.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="js/app.js"></script>
</body>
</html>
二、JS
(function (window) {
'use strict';
// 里面的变量都是局部变量,除非绑定在window上
// 书写本地存储的存取方法
window.storage = {
getStorage(){
// 获取本地存储,并转换成json对象
return JSON.parse(window.localStorage.getItem('todos')||'[]');
},
setStorage(json){
// 把传入的json对象转成json字符串,存入本地存储
window.localStorage.setItem('todos',JSON.stringify(json));
}
}
// 创建一个vue实例
window.app = new Vue({
el:".todoapp",
data:{
tasks:window.storage.getStorage(),
newTask:"",
isEditing:-1,
status:true,
count:0,
flag:location.hash=="#/active"?({
completed:false}):(location.hash=="#/completed"?({
completed:true}):"")
},
directives:{
"todo-focus":function(el,binding){
if(binding.value){
el.focus()
}
}
},
computed:{
activeNum(){
this.count = 0;
this.tasks.forEach((task)=>{
if(!task.completed){
this.count++;
}
})
return this.count;
},
isShow(){
for(var i=0;i<this.tasks.length;i++){
if(this.tasks[i].completed){
return true;
}
}
return false;
},
Shown(){
if(this.tasks.length>0){
return true;
}
}
},
methods:{
show(i){
if(this.flag===""){
return true;
}else if(this.flag.completed===i){
return true;
}
window.storage.setStorage(this.tasks);
},
clearAll(){
this.tasks = this.tasks.filter(task=>!task.completed);
window.storage.setStorage(this.tasks);
},
toggleAll(){
this.tasks.forEach((task)=>{
task.completed = this.status
});
this.status = !this.status;
// 同步到本地存储中
window.storage.setStorage(this.tasks);
},
remove(id){
this.tasks = this.tasks.filter(task=>{
return task.id!=id
})
// 同步到本地存储中
window.storage.setStorage(this.tasks);
},
add(){
var task = {
title:this.newTask,
completed:false,
id:Date.now()
}
if(task.title!=''){
this.tasks.push(task);
}
// 输入完成后,清空文本框
this.newTask = ""
// 同步到本地存储中
window.storage.setStorage(this.tasks);
}
}
})
// 监控路由的变化
window.onhashchange = function(){
console.log(location.hash);
// 专门在vue实例里面声明一个变量由于标识当前是在哪个路由
if(location.hash=="#/active"){
window.app.flag = {
completed:false}; //active就是要显示未完成任务,flag最好有意义
return;
}else if(location.hash=="#/completed"){
window.app.flag = {
completed:true}; //completed就是要显示已完成任务,flag最好有意义
return;
}else{
// 如果是其他路由,都显示全部任务
window.app.flag = "";
return;
}
}
})(window);
结束语
你那么可爱,肯定会点赞,一起加油!
来源:oschina
链接:https://my.oschina.net/u/4361028/blog/4705308