-------------------------------------------
todo list 作业
ps: 我完成的效果和老师教的有一些不同
但是老师所实现的我也都实现了
1. 我在 删除后面加入了 【编辑】 可以直接点击编辑 也可以双击编辑
2. 当单机任务完成时 后面的【删除】【编辑】 不会随鼠标移入移出改变 而是点击后一直存在
------------------------------------------------
html 源码
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>todo list</title>
<link rel="stylesheet" type="text/css" href="./todo-list.css" />
</head>
<body>
<div id="head">
任务计划列表
</div>
<div id="main">
<div class="name">添加任务</div>
<!-- 添加键盘事件 并将input的value值 用intext获取 -->
<input type="text" placeholder='请输入任务' v-model='intext' v-on:keyup.enter='addList' v-focus />
<!-- 添加隐藏的指令 并给出依据 show show不等于0时展示 -->
<div class="task" v-show="show">
<span>{{nochecked}}个任务未完成</span>
<div class="task_type">
<a href="#all">所有任务</a>
<a href="#unfinished">未完成任务</a>
<a href="#finish">完成任务</a>
</div>
</div>
<div class="list">
<ul>
<!-- 循环产生li标签及其内部标签 并判断是否有内容 没有则不展示 因为在初始化时会产生一个空标签所以才会判断 以免产生空任务 -->
<li v-for='item in filtereitems' v-show='item.text' id="oli" >
<!-- 动态添加class 当点击选中时添加hidd 目的是显示复选框和删除
input 的选择中状态由 ischecked 的值决定 -->
<div id="box"><input type="checkbox" class="
chex" :class='{hidd:item.isChecked,dblclickhidd:item.showed}' v-model='item.isChecked' /></div>
<!-- class和前面一样里面包含选中时出现删除线 标签内的内容由text决定 而text由输入内容决定 -->
<!-- 点击重新编辑任务 即点击时隐藏原任务 并且出现输入框 输入框内容为元任务内容-->
<span v-on:click='clickselect(item)' :class='{hidd:item.isChecked}'
v-on:dblclick='showinput(item)' v-show='!item.showed'>{{item.text}}</span>
<!-- 输入框的值用newtext表示 输入完成后将值传给 item.text v-show 给item中定义showed 初始weifalse 双击后 为true 按回车时将newtext的值传给text v-focu 自定以聚焦函数 当双击时获取焦点 失去焦点时执行和回车相似功能 -->
<input type="text" id="newtext" v-model = 'newtext' v-show='item.showed' v-on:keyup.enter='addnewtext(item)' v-focu='item.showed' v-on:blur='blurhidd(item)'/>
<!-- class相同 添加点击删除函数 并且函数接受当前的item,由于去判断在数组中的索引 确定位置 -->
<a href="javascript:void(0)" :class='{Ahidd:item.isChecked,dblclickhidd:item.showed}' v-on:click='deletList(item)'>删除</a>
<a href="javascript:void(0)" :class='{Ahidd:item.isChecked,dblclickhidd:item.showed}' v-on:click="showinput(item)">编辑</a>
</li>
</ul>
</ul>
</div>
</div>
<script type="text/javascript" src='./vue.js'></script>
<script type="text/javascript" src='./todo-list.js'></script>
</body>
</html>
js 源码
// 实例化
//自定义指令 自动获取焦点
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
});
// 存取数据 localStorage
var store = {
//保存数据
save:function(key,value){
localStorage.setItem(key,JSON.stringify(value));
},
//获取数据
fetch:function(key){
return JSON.parse(localStorage.getItem(key)) || [] ;
}
}
//三种情况
var filter ={
all:function(items){
return items;
},
unfinished:function(items){
return items.filter(function(items){
return !items.isChecked;
})
},
finish:function(){
return items.filter(function(items){
return items.isChecked;
})
},
}
//数据
var items = store.fetch('classs'); // 获取保存的数据
var main = new Vue({
el:"#main",
data:{
items:items,
intext:'',
show: items.length, // 添加判断是否展示输入框下的任务栏依据
newtext:'',
visibility:'all' , // 通过属性变化 筛选数据
},
// 计算属性
computed:{
nochecked:function(){
return this.items.filter(function(items){
return !items.isChecked;
}).length;
},
filtereitems:function(){
return filter[this.visibility] ? filter[this.visibility](items) : items ;
}
},
// 自定义局部指令
directives: {
focu: {
// 指令的定义---
update:function (el,binding) {
// 聚焦元素
if(binding.value)
{ el.focus()}
},
}
},
//监控
watch:{
//浅监控 只能监控items一层 内部变化不会监控
// items:function(){ // 监控items属性 items变化 执行函数
// store.save('classs',this.items);
// }
//深监控
items:{
handler:function(){
store.save('classs',this.items);
},
deep:true,
}
},
methods:{
// 添加任务函数
addList: function(){
if(this.intext.length!=0) // 判断输入框是否有输入内容
{
this.items.push({
text: this.intext, // 将输入内容添加到 items.text内
isChecked:false, // 使刚输入的未被选中 (注意即使不添加这句也会不选中
showed:false, // 但是数组items内相应位置就不会出现ischecked 会使后面需要选中时出现问题)
});
this.show = this.show+1; //每添加一个任务 任务的总个数加一
}
// 清空输入框内容
this.intext = '';
},
//双击重新编辑任务
showinput: function(lsi){
var om = this.items.indexOf(lsi); //获取相应的索引值
console.log(om);
//显示输入框
this.items[om].showed = true ;
this.newtext = this.items[om].text;
// 隐藏复选框 删除
this.items[om].isChecked = false;
console.log(this.items[om].showed );
//输入框自动获取焦点
},
//元素失去焦点时
blurhidd:function(lsi){
var om = this.items.indexOf(lsi); //获取相应的索引值
this.items[om].showed = false;
// 判断是否输入内容 如果输入为空则不改变元任务
if(this.newtext.length != 0)
{
this.items[om].text = this.newtext;
}
},
//回车添加新任务
addnewtext:function(lsi){
var om = this.items.indexOf(lsi); //获取相应的索引值
// 隐藏输入框显示任务
this.items[om].showed = false;
// 判断是否输入内容 如果输入为空则不改变元任务
if(this.newtext.length != 0)
{
this.items[om].text = this.newtext;
}
},
// 失去焦点是
// 点击文字选中复选框
clickselect:function(lsi){
console.log(this.items.indexOf(lsi));
var om = this.items.indexOf(lsi); //获取相应的索引值
this.items[om].isChecked = !this.items[om].isChecked; // 当点击相应任务时
// 选择的状态发生改变
},
// 点击删除
deletList: function(lsi){
var om = this.items.indexOf(lsi);
// this.items[om].text=''; //这样并没有完全从数组清除
// 当点击删除时 未完成任务数量变化
// 变化依据任务是否已经被选中而变化
// 不能将移出数组先执行 这样就会导致无法判断是否之前已经被选中
this.show= this.show-1; // 任务总数减一 如果总数等于0时 隐藏
this.items.splice(om,1); // 移出相应任务
}
}
});
function watchHash(){
var hash = window.location.hash.slice(1);
// 改变值
main.visibility=hash;
};
watchHash();
window.addEventListener('hashchange',watchHash);
css 源码
body{padding: 0;margin:0; font-size: 14px; font-family: '微软雅黑'; background-color: #EFEFEF;}
ul,li,a,div,input,span {padding: 0; margin:0;}
a{text-decoration: none; color: #000;}
ul,li {list-style-type: none;}
/*顶部布局*/
#head {
width: 100%;
height: 50px;
font-size: 18px;
font-weight: bold;
line-height: 50px;
text-align: center; }
#main {
width: 400px;
margin:5px auto;
}
#main .name {
font-size: 16px;
font-weight: bold;
}
#main input {
width: 400px;
height: 35px;
outline: none;
}
#main .task{
margin:10px 0;
height: 32px;
overflow: hidden;
line-height: 32px;
}
#main .task span {
display: block;
height: 30px;
float: left;
}
#main .task .task_type{
float: right;
}
#main .task .task_type a{
display: block;
height: 30px;
padding: 0 5px;
line-height: 30px;
border:1px solid #ccc;
text-decoration: center;
float: left;
margin-left: 10px;
}
#main .list {
width: 400px;
clear: both;
}
#main .list ul{
width: 400px;
}
#main .list ul li {
width: 400px;
height: 30px;
padding: 5px 0;
line-height: 30px;
display: block;
overflow: hidden;
background-color: #fff;
border-bottom:1px solid #ccc;
}
#main .list ul li #newtext{
height: 28px;
border:1px solid #ccc;
width: 250px;
float: left;
}
#main .list ul li #box {
float: left;
width: 16px;
height:16px;
margin:7px 0;
}
#main .list ul li .chex{
display: none;
width: 16px;
height:16px;
}
#main .list ul li:hover a{
display: block;
}
#main .list ul li a:hover {
color: red;
text-decoration:underline;
}
#main .list ul #oli:hover .dblclickhidd{
display: none;
}
#main .list ul li:hover .chex{
display: block;
}
#main .list ul li .hidd {
display: block;
color: #ccc;
text-decoration: line-through;
}
#main .list ul li .Ahidd {
display: block;
/*color: #ccc;*/
/*text-decoration: line-through;*/
}
#main .list ul li span {
display: block;
float: left;
margin-left: 20px;
}
#main .list ul li a{
color: #ccc;
display: none;
float: left;
margin-left: 20px;
}
------------------------
效果展示