一、文章内容
TodoList结构搭建HTML代码
TodoList样式编写Css代码
TodoList行为表现JavaScript代码
二、项目展示
项目介绍
Todolist是一个基于B/S模式开发的待办事项软件,主要功能是离线记录用户的待办事项和已经完成的事情,基于html+css+js实现,涉及到的知识主要是事件监听和数据缓冲技术.
项目展示GIF
图1 项目功能展示
项目中的亮点:
- 点击代办事项可以让输入框获取焦点,我愿称之为:
梦幻联动效果
. - 在输入框里按下回城键调用add()函数,自动判断:
自动检测
. - 在左下角有一个“我要到上面”的标签,点击就可以快速回到顶部,我称为:
一键返航
.
三、代码细节
Html部分
相信大家在学习过前导课的基础上我们学习下面代码会轻松很多,不过我也会一行一行给大家解释的。
我们讲html页面分为顶部和内容部分,也就是header和section部分,第一个header包裹的内容就是todolist的头部,如图2所示.图2 todolist顶部
夹在header和footer中间的section为页面主题部分,也就是项目展示的地方,里面包含了todo和done列表,如图3所示.
图3 网页中心界面
html框架搭建总体比较简单所以大家可以根据自己的想法设计,或者跟着我这个框架敲一遍.下面是所有的html代码:
<header> <section> <div id="form"> <label for="title"> todo </label> <input type="text" id="title" placeholder="输入todolist"> </div> </section> </header> <section> <h2>需要进行的事情<span id="todocount">0</span></h2> <ol id="todolist" class="demo-box"></ol> <h2>已经完成的事情<span id="donecount">0</span></h2> <ul id="donelist"></ul> </section> <footer> <a href="#top" id="mao">我要到上面</a> </footer>
Css样式代码
当然要让css和html联动必须在html中引入自己的css文件,语法如下
<link rel="stylesheet" href="main.css">
因为我的css样式新建了文件,并且跟index.html在同根目录下,所以可以这样引入,路径不同的读者可以自己修改src的属性值.
如果自己有设计的同学可以直接看下面JavaScript逻辑代码了,这块主要负责美化样式.body{}选择器是将body标签选中,将内外边距都设置为0,方便后期开发,如果不设置该属性会默认有偏移.剩下俩个是整个网页的字体大小跟背景色全局生效.
html,body{}这个选择器里的属性只有一个scroll-behavior这个在前导课里讲过,功能使得页面滑动平滑.
header{}这个选择器设置了顶部的高度和背景色.
section{}选择器设置了主要内容居中显示,margin:0 auto;auto是关键.
#mao{}id选择器主要通过浮动设置了一键返航的位置.
label{}选择器是待办事项这几个字的位置也是使用了浮动,这是左浮动,通过line-hight设置垂直方向的字体位置,如果跟父级元素高度一样,里面的字就可以实现垂直居中了.cursor:pointer;设置了鼠标悬浮的样式,我记得有6种样式,大家可以自己尝试.
header input{}组合选择器主要负责的是输入框的内容,这里设置了右浮动,同时设置了宽度50%,意思是只占父级元素的一半宽度,text-indent是输入框的缩进,单位像素,自己可以测试一个合适的value,我选择10个像素,border-radius: 5px; 这个属性是输入框的圆角,值越大越⚪.box-shadow: 0 1px 0 rgba(255,255,255,0.24), 0 1px 6px rgba(0,0,0,0.45) inset; 这个属性设置了输入框的盒子阴影,具体参数大家可以去看看CSS box-shadow 属性 (w3school.com.cn).border:none; 这样设置输入框的外边框就没了.
input:focus{}伪类选择器中outline-width: 0; 设置了输入框的边框,也就是当输入框获取焦点,默认是有边框的,这样设置就可以解决这个问题.
h2{}选择器标签只加了一个定位属性,原因是为了span可以很好的定位.
span{}选择器是todolist和donelist的个数,也就是最左边哪个圆点,
line-height: 20px; text-align: center;
是让文字水平和垂直居中的,其他属性都在上面介绍过,所以不一一介绍了.ol,ul{}选择器是todolist和donelist列表外部标签list-style: none; 该属性可以让有序列表和无序列表的数字和圆点消失,加强了美观.
li input{}选择器是每个任务item的选择框样式,设置了position:absolute,进行了元素定位,然后设置了鼠标悬浮的样式.
li{}选择器设置了相对的位置,border-radius: 3px;
border-left: 6px solid #FFB800;
border-right : 6px solid #FFB800; 分别设置了选择框的左右边框,和item的圆角.li:hover{}伪类选择器设置了todolist和donelist中item触摸上去颜色变为蓝色color:#01AAED;
ul li{}组合选择器设置了完成item的透明色和左右边框的颜色border-left: 5px solid #c2c2c2;
border-right: 5px solid #c2c2c2;
opacity: 0.5;最后使用@media screen and (min-width){}选择器设置了自适应布局.
下面是css的所有代码:body{ padding: 0; margin: 0; font-size: 16px; background:#dddddd; } html,body{ scroll-behavior: smooth ; } header{ height: 50px; background: #333; } section{ margin: 0 auto; } #mao{ float:right; margin-right: 40px; margin-bottom: 20px; } label{ float: left; width: 100px; line-height: 50px; color: #DDD; font-size: 24px; cursor:pointer; } header input{ float: right; width: 50%; height: 25px; margin-top: 12px; /* 所经 text_indent */ text-indent: 10px; border-radius: 5px; box-shadow: 0 1px 0 rgba(255,255,255,0.24), 0 1px 6px rgba(0,0,0,0.45) inset; border:none; } input:focus{ outline-width: 0; } h2{ position: relative ; } span{ position: absolute; top: 10px; right: 5px; display: inline-block; padding: 0 5px; height: 20px; border-radius: 20px; background-color: seagreen; line-height: 20px; text-align: center; color:whitesmoke; font-size: 14px; } ol,ul{ padding: 0; list-style: none; } li input{ position:absolute; top:2px; left: 10px; width: 22px; height: 22px; cursor: pointer; } li{ height: 32px; line-height: 32px; background-color: #fff; position: relative; margin-bottom: 10px; padding: 0 45px; border-radius: 3px; border-left: 6px solid #FFB800; border-right : 6px solid #FFB800; } li:hover { color:#01AAED; } ul li{ border-left: 5px solid #c2c2c2; border-right: 5px solid #c2c2c2; opacity: 0.5; } @media screen and (max-device-width: 620px) {section{width:96%;padding:0 2%;}} @media screen and (min-width: 620px) {section{width:600px;padding:0 10px;}}
JavaScript逻辑代码
站在产品经理角度分析:如何在完成基本需求的基础上,使得用户体验更好?
答案:1.点击todolist(待办事务)输入框自动获取焦点.
2.在输入框里回车即可提交事务,不必加button.3.在任务数量较多的时候提供一家返回功能.当然在满足上述功能后我们需要弄清楚JavaScript的逻辑代码,其实只有todolist和donelist需要我们更新,只要2者发生变化我们就需要load()加载一次,所以load()需要写为一个函数多次调用,再其次就是将add()按键触发也写为一个函数方便,在里边修改规则,这是简单的解耦,最后我门将pd()和pd2()封装为俩个函数分别将不同checkbox发出的按键逻辑进行代码编写,方便修改对应逻辑.
在明白需求后开始写代码,每个函数都写了一个小标题进行了函数解释,最后将文末的俩行监控代码加进去组成js代码引入到html页面里即可.图4 简易框架图
只要打开页面就要启用监听事件,将load()加载,这样做的好处是无论你是第一次打开网站,还是第二次都可以准确无误的加载item.语法是:**window.addEventListener(“load”, load); //页面加载完毕调用load函数 **
然后监听输入框按键,语法规则document.addEventListener(“keyup”, add); 然后编写对应的add()函数即可.
函数解释load():
第一行和第二行是获取todolist和donelist个数的元素(小圆点),方便下面对数量进行更新,使用localStorage.todo读取本地缓存中的todo数据,如果有数据,进行数据解析将缓冲解析为JavaScript的数组,然后声明一个todohtml变量保存item数据=》然后根据todo的长度for循环,根据规则加li标签最后使用JavaScript操作dom找到todolist的元素将innerhtml赋值为todohtml即可将todolist渲染完成.最后简单判断一下todo的长度,如果有长度,将控制item数量的元素找到然后修改value,如果没长度也就是第一次打开默认为0!todolist和donelist渲染方式一样,我就不多解释了,请认真结合文字读这段代码.你一定可以读懂.
function load(){ todocount = document.getElementById("todocount"); donecount = document.getElementById("donecount"); if(localStorage.todo){ todo = JSON.parse(localStorage.todo); var todohtml = ""; for(var i = 0 ; i < todo.length; i++){ todohtml += '<li><input type="checkbox" cheched onclick="pd(this)" value="'+ i +'" name="' + todo[i] + '">' + todo[i] + '</li>'; } document.getElementById('todolist').innerHTML = todohtml; if(todo.length!=0) { todocount.innerHTML = todo.length; } else{ todocount.innerHTML = 0; } } if(localStorage.done){ done = JSON.parse(localStorage.done); var donehtml = ""; for(var i = 0 ; i < done.length; i++){ donehtml += '<li><input type="checkbox" cheched onclick="pd2(this)" value="'+ i +'" name="' + done[i] + '">' + done[i] + '</li>'; } document.getElementById('donelist').innerHTML = donehtml; if(done.length!=0){ donecount.innerHTML = done.length; }else{ donecount.innerHTML = 0 ; } } }
函数解释add():
add()函数是当回车键触发且判断加入的事件不为空更新本地缓冲的一个函数并且load().
函数第一行使用JavaScript操作dom获取到input输入框元素,然后判断按键是否为13也就是回车键的Unicode码==13 并且输入框的内容不为空,然后将todo使用堆栈操作添加输入框的内容,接着更新本地缓冲(需要json变为字符串),然后将输入框内容置为空,然后就可以加载load()函数更新页面了.如果不满足条件弹出alert信息框.
完整代码如下:function add(e){ info = document.getElementById('title') ; if(e.keyCode == 13 && info.value != ''){ todo.push(info.value); localStorage.todo = JSON.stringify(todo); info.value = ''; load(); }else if(e.keyCode == 13 && info.value == ''){ alert('输入内容提交'); } }
函数解释pd():
细心的读者一定发现这个函数在todolist的每一个item里有个checkbox然后绑定了一个onclicked的事件,当你选择该选择框的时候就会调用pd()函数,该函数是将todolist里的元素删除并且添加到donelist的.
done.push(e.name)将本元素的name加到donelist里,为什么可以这样操作? 因为在load()函数里写了
'<li><input type="checkbox" cheched onclick="pd(this)" value="'+ i +'" name="' + todo[i] + '">' + todo[i] + '</li>';
看到name属性的值是todo[i]item的值,所以可以直接push,然后在todolist里删除该item使用,splice函数,该函数专门为数组设计的用法挺多,详细了解的读者可以自行百度,因为input的value记录的是该item的index下标所以可以直接pareint转换,既然todo和done都更新了,我们接着将浏览器缓冲更新一下就是**localStorage.done = JSON.stringify(done);
localStorage.todo = JSON.stringify(todo);** 这样,接着在列表改动后继续load()重载一下,下面是代码:
function pd(e){ done.push(e.name); todo.splice(parseInt(e.value),1); localStorage.done = JSON.stringify(done); localStorage.todo = JSON.stringify(todo); load(); }
函数解释pd2():
既然有pd()肯定页有pd2(),一个操作todo里面的checkbox,一个操作done里面的checkbox,好了言归正传,pd2()和pd()操作逻辑一样,但是实体却不一样,一个是todo数组push一个是done数组push,读者可以自行比较,这段代码相对简单,在todo和done数组修改完毕,接着就是更新本地缓冲了,然后load()函数.
function pd2 (e){ done.splice(parseInt(e.value),1); todo.push(e.name); localStorage.done = JSON.stringify(done); localStorage.todo = JSON.stringify(todo); load(); }
将上述代码和下面这俩行代码组合成一个js文件就是JavaScript所有代码了.
window.addEventListener("load", load); //页面加载完毕调用load函数 document.addEventListener("keyup", add); //按键监听
能读到这里的小伙伴属实不容易,相信你能坚持这么久你一定可以自己独立开发todolist程序了,恭喜你呀.
四、参照文献
CSS 简介 (w3school.com.cn)
JavaScript 教程 | 菜鸟教程 (runoob.com)