您的位置:首页 > 产品设计 > UI/UE

【IMWeb训练营作业】Todo list

2017-04-20 02:28 691 查看

【IMWeb训练营作业】Todo list

最近参加腾讯课堂的IMWeb训练营,学习Vue.js,虽然之前已经了解过Vue.js,自己也跟着Vue.js官方教程走了一边,不过因工作上技术栈一直处于Angular.js 1.x,公司各种赶项目,然后就没深入去学习(其实就为自己的懒找借口,orz), 而在这课堂里面也学到了不少,进一步深入了解了虚拟dom,前端组件化,还有一些目前前端工程化等,废话少说,还是简单总结以下本次的Todo list;

一、涉及知识点:

内置指令(v-model, v-on (缩写:‘@’),v-show,v-if, v-bind (缩写:‘:’),v-for)

计算属性 computed

观察 watcher

自定义指令directives

localStorage的使用

二、简单功能任务

添加任务,回车添加(v-model, v-on使用)

删除任务(v-on使用)

编辑任务 (自定义指令使用-directives )

筛选任务 (计算属性使用-computed)

展示任务(v-show,v-if, v-bind,v-for)

存取数据(localStorage,观察 watcher )

三、任务核心

(一)、 目录结构



(二)、 核心文件

package.json

使用browser-sync浏览器同步测试调试,

{
"name": "todo-list",
"version": "1.0.0",
"description": "todo-list demo",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "browser-sync start --server --files \"src/css/*.css, *.html\""
},
"keywords": [
"vue"
],
"author": "Hung",
"license": "ISC",
"dependencies": {
"vue": "^2.2.6"
},
"devDependencies": {
"browser-sync": "^2.18.8"
}
}


index.html

基本上直接采用课堂页面结构

<!DOCTYPE html>
<html lang="zh-cn">

<head>
<meta charset="UTF-8">
<title>Todo list</title>
<link rel="stylesheet" href="src/css/index.css">
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>

<body>
<!-- top /s -->
<div class="page-top">
<div class="page-content">
<h2>任务计划列表</h2>
</div>
</div>
<!-- top /e -->

<!-- main /s -->
<div class="main">

<h3 class="big-title">添加任务:</h3>

<!-- task-input -->
<input placeholder="请添加任务(提示:回车即可添加任务)"
class="task-input"
type="text"
v-model="todo"
v-on:keyup.13="addTodo" />

<!-- task-count -->
<ul class="task-count" v-show="list.length">
<!-- 未完成任务 -->
<li>{{noCheckeLength}}个任务未完成</li>

<!-- 任务状态 -->
<li class="action">
<a href="#all" :class="{active:visibility === 'all'}">所有任务</a>
<a href="#unfinished" :class="{active:visibility === 'unfinished'}">未完成的任务</a>
<a href="#finished" :class="{active:visibility === 'finished'}">完成的任务</a>
</li>

</ul>

<h3 class="big-title">任务列表:</h3>

<!-- task -->
<div class="tasks">
<!-- 空数据提醒 -->
<span class="no-task-tip" v-show="!list.length">还没有添加任何任务</span>

<!-- todo 列表 -->
<ul class="todo-list">
<li class="todo" v-for="item in filtered
10bd6
List" :class="{completed: item.isChecked,editing: item === editorTodos}">
<div class="view">
<input class="toggle" type="checkbox" v-model="item.isChecked" />
<label @dblclick="editorTodo(item)">{{ item.title }}</label>
<button class="destroy" @click="deleteTodo(item)"></button>
</div>
<input  class="edit"
type="text"
v-model="item.title"
v-foucs="editorTodos === item"
@blur="editorTodoed(item)"
@keyup.13="editorTodoed(item)"
@keyup.esc="cancelTodo(item)" />
</li>
</ul>

</div>
</div>
<!-- top /e -->

<script src="./src/app.js"></script>
</body>

</html>


app.js

// 存取localStorage中的数据
var store = {
// 存
save(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
// 取
fetch(key) {
return JSON.parse(localStorage.getItem(key)) || [];
}
};

// 过滤情况 all finished unfinished
var filter = {
// all--> 所有任务
all: function(list) {
return list;
},
// finished --> 完成任务
finished: function(list) {
return list.filter(function(item) {
return item.isChecked;
})
},
// unfinished --> 未完成任务
unfinished: function() {
return list.filter(function(item) {
return !item.isChecked;
})
}
};

// 取出本地数据
var list = store.fetch("TODO_LIST");

var vm = new Vue({
el: ".main", // 挂载元素
data: {
list: list,
todo: "",
editorTodos: '',
beforeTitle: '',
visibility: "all"
},
// 监测
watch: {
list: {
handler: function() {
store.save("TODO_LIST", this.list);
},
deep: true // 深度监测
}
},
// 计算属性
computed: {
noCheckeLength: function() {
return this.list.filter(function(item) {
return !item.isChecked
}).length
},
filteredList: function() {
return filter[this.visibility] ? filter[this.visibility](list) : list;
}
},
// 方法
methods: {
// 添加任务
addTodo() {
this.list.push({
title: this.todo,
isChecked: false
});
this.todo = '';

},
// 删除任务
deleteTodo(todo) {
var index = this.list.indexOf(todo);
this.list.splice(index, 1);
},
// 编辑任务
editorTodo(todo) {
this.beforeTitle = todo.title;
this.editorTodos = todo;
},
// 编辑任务成功
editorTodoed(todo) {
this.editorTodos = '';
},
// 取消编辑任务
cancelTodo(todo) {
todo.title = this.beforeTitle;
this.beforeTitle = '';
this.editorTodos = '';
}
},
// 指令
directives: {
"foucs": {
// 钩子函数,el为元素,binding是表达式的值
update(el, binding) {
if (binding.value) {
el.focus();
}
}
}
}
});

// 获取hash --> 得到显示数据属性状态
function watchHashChange() {
var hash = window.location.hash.slice(1);
vm.visibility = hash;
}

watchHashChange();

window.addEventListener("hashchange", watchHashChange);


index.css

直接引入课堂样式

body{margin:0;background-color:#fafafa;font:14px 'Helvetica Neue',Helvetica,Arial,sans-serif}
h2{margin:0;font-size:12px}
a{color:#000;text-decoration:none}
input{outline:0}
button{margin:0;padding:0;border:0;background:0 0;font-size:100%;vertical-align:baseline;font-family:inherit;font-weight:inherit;color:inherit;outline:0}
ul{padding:0;margin:0;list-style:none}
.page-top{width:100%;height:40px;background-color:#db4c3f}
.page-content{width:50%;margin:0 auto}
.page-content h2{line-height:40px;font-size:18px;color:#fff}
.main{width:50%;margin:0 auto;box-sizing:border-box}
.task-input{width:99%;height:30px;outline:0;border:1px solid #ccc}
.task-count{display:flex;margin:10px 0}
.task-count li{padding-left:10px;flex:1;color:#dd4b39}
.task-count li:nth-child(1){padding:5px 0 0 10px}
.action{text-align:center;display:flex}
.action a{margin:0 10px;flex:1;padding:5px 0;color:#777}
.action a:nth-child(3){margin-right:0}
.active{border:1px solid rgba(175,47,47,.2)}
.tasks{background-color:#fff}
.no-task-tip{padding:10px 0 10px 10px;display:block;border-bottom:1px solid #ededed;color:#777}
.big-title{color:#222}
.todo-list{margin:0;padding:0;list-style:none}
.todo-list li{position:relative;font-size:16px;border-bottom:1px solid #ededed}
.todo-list li:hover{background-color:#fafafa}
.todo-list li.editing{border-bottom:none;padding:0}
.todo-list li.editing .edit{display:block;width:506px;padding:13px 17px 12px 17px;margin:0 0 0 43px}
.todo-list li.editing .view{display:none}
.todo-list li .toggle{text-align:center;width:40px;height:auto;position:absolute;top:5px;bottom:0;margin:auto 0;border:none;-webkit-appearance:none;appearance:none}
.toggle{text-align:center;width:40px;height:auto;position:absolute;top:5px;bottom:0;margin:auto 0;border:none;-webkit-appearance:none;appearance:none}
.toggle:after{content:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="40" fill="none" stroke="#ededed" stroke-width="3"/></svg>')}
.toggle:checked:after{content:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="40" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>')}
.todo-list li label{white-space:pre-line;word-break:break-all;padding:15px 60px 15px 15px;margin-left:45px;display:block;line-height:1.2;transition:color .4s}
.todo-list li.completed label{color:#d9d9d9;text-decoration:line-through}
.todo-list li .destroy{display:none;position:absolute;top:0;right:10px;bottom:0;width:40px;height:40px;margin:auto 0;font-size:30px;color:#cc9a9a;margin-bottom:11px;transition:color .2s ease-out}
.todo-list li .destroy:hover{color:#af5b5e}
.todo-list li .destroy:after{content:'×'}
.todo-list li:hover .destroy{display:block}
.todo-list li .edit{display:none}
.todo-list li.editing:last-child{margin-bottom:-1px}


四、展示

所有任务



未完成任务



完成任务



五、小结

本次的Todo list 为经典的入门练习,基本能通过这来掌握一些基本的指令和语法,同时, 对于接触过Angular.js总体来说,很多地方是比较相似的,这从内置的指令和一些语法可以看得出,但是Vue.js 更加灵活,毕竟Vue.js 借鉴了Angular.js和React.js,当然也少不了官网教程、文档的友好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  vue-js todo-list