使用js写了一个任务管理列表,数据存储在本地,可以实现:自动计算任务完成时间、标记完成、录入、删除任务。主要是练习和熟悉一些DOM操作~而且日常记录任务也可以使用这个自己设计的网页,成就感upup!
实现效果如下图所示~
接下来就来跟我一起定制自己专属的任务列表吧~
一、代码结构
1.html部分
用html搭建一个简单的骨架,包括标题、实时时间显示模块、任务录入模块、任务清单的标题部分。
2.css部分
用css实现两个大盒子在屏幕上的布局,再设置相应的字体、边框等样式。
3.js部分
前面两个部分的代码都非常简单。js才是实现本项目的重头戏。js部分包括以下几个模块:
(1)任务清单渲染模块
(2)任务完成勾选模块
(3)实时日期渲染模块
(4)表单录入模块
(5)删除操作模块
接下来跟着我完善各部分代码吧~
二、代码实现
1.html部分
分为两个大盒子:plus盒子用于新增任务,show盒子用于展示清单。
按照预想的架构,把标题和文本框,下拉表单,按钮,任务列表的骨架一个个摆上去就好了。
完成后的效果如图:
以下为源码:
<div class="plus"><h1>新增任务</h1><p class="myDate">今天是:2023/8/10 </p><form class="info" autocomplete="off">任务:<input type="text" class="uname" name="uname">完成期限:<select name="udate" class="udate"><option value="六小时">六小时</option><option value="一天">一天</option><option value="两天">两天</option><option value="三天">三天</option><option value="一星期">一星期</option></select><button class="add">录入</button></form></div><div class="show"><h1>任务清单</h1><table><thead><tr><th>全选<input type="checkbox" id="checkAll"></th><th>任务</th><th>完成期限</th><th>操作</th></tr></thead><tbody><!-- <tr><td><input type="checkbox" class="ck"></td><td>看仁医</td><td>今天</td><td>删除</td></tr> --></tbody></table></div> `<div class="plus"> <h1>新增任务</h1> <p class="myDate">今天是:2023/8/10 </p> <form class="info" autocomplete="off"> 任务:<input type="text" class="uname" name="uname"> 完成期限:<select name="udate" class="udate"> <option value="六小时">六小时</option> <option value="一天">一天</option> <option value="两天">两天</option> <option value="三天">三天</option> <option value="一星期">一星期</option> </select> <button class="add">录入</button> </form> </div> <div class="show"> <h1>任务清单</h1> <table> <thead> <tr> <th>全选<input type="checkbox" id="checkAll"></th> <th>任务</th> <th>完成期限</th> <th>操作</th> </tr> </thead> <tbody> <!-- <tr> <td><input type="checkbox" class="ck"></td> <td>看仁医</td> <td>今天</td> <td>删除</td> </tr> --> </tbody> </table> </div> `<div class="plus"> <h1>新增任务</h1> <p class="myDate">今天是:2023/8/10 </p> <form class="info" autocomplete="off"> 任务:<input type="text" class="uname" name="uname"> 完成期限:<select name="udate" class="udate"> <option value="六小时">六小时</option> <option value="一天">一天</option> <option value="两天">两天</option> <option value="三天">三天</option> <option value="一星期">一星期</option> </select> <button class="add">录入</button> </form> </div> <div class="show"> <h1>任务清单</h1> <table> <thead> <tr> <th>全选<input type="checkbox" id="checkAll"></th> <th>任务</th> <th>完成期限</th> <th>操作</th> </tr> </thead> <tbody> <!-- <tr> <td><input type="checkbox" class="ck"></td> <td>看仁医</td> <td>今天</td> <td>删除</td> </tr> --> </tbody> </table> </div> `
2.css部分
实现思路是:
1.首先用标准流布局加和浮动布局,将plus和show两个大盒子的宽度设置好并摆放好。
根据预期效果,plus盒子容纳的内容较少,只包含时间实时显示模块,标题,以及录入模块,因此宽度设置为400px;而show盒子容纳的清单大小会根据用户录入的量增加而增加,包含的内容较多,因此宽度设置为900px,高度不予设置,但设置了底部内边距padding-bottom为40px,来保证盒子的高度会根据需要自动伸缩,并且使内边距较为美观。
布局部分的代码如下:
* {margin: 0;padding: 0;}.plus {margin: 30px 10px;float: left;width: 400px;background-color: #e9f1f7;border: 2px dotted #a5b9d2;}.show {margin: 30px 10px;float: left;width: 900px;padding-bottom: 40px;background-color: #e9f1f7;border: 2px dotted #a5b9d2;}* { margin: 0; padding: 0; } .plus { margin: 30px 10px; float: left; width: 400px; background-color: #e9f1f7; border: 2px dotted #a5b9d2; } .show { margin: 30px 10px; float: left; width: 900px; padding-bottom: 40px; background-color: #e9f1f7; border: 2px dotted #a5b9d2; }* { margin: 0; padding: 0; } .plus { margin: 30px 10px; float: left; width: 400px; background-color: #e9f1f7; border: 2px dotted #a5b9d2; } .show { margin: 30px 10px; float: left; width: 900px; padding-bottom: 40px; background-color: #e9f1f7; border: 2px dotted #a5b9d2; }
2.用css选择器一个个选中其中的标题、表单等元素设置对应的样式即可。
这部分没什么严格要求,根据自己的喜好设置即可。注意各种基础选择器和复合选择器的配合使用哦~
实现代码如下:
.plus h1 {text-align: center;color: #333;margin: 20px 0;font-size: 20px;}.show h1 {text-align: center;color: #333;margin: 20px 0;}table {margin: 0 auto;width: 850px;border-collapse: collapse;color: #004085;}th {padding: 10px;background: #cfe5ff;font-size: 20px;font-weight: 400;}td,th {border: 1px solid #b8daff;}td {padding: 10px;color: #666;text-align: center;font-size: 16px;}tbody tr {background: #fff;}tbody tr:hover {background: #e1ecf8;}.info {width: 400px;margin: 30px auto;text-align: center;}.info input,.info select {width: 80px;height: 27px;outline: none;border-radius: 5px;border: 1px solid #b8daff;padding-left: 5px;box-sizing: border-box;margin-right: 15px;}.info button {width: 60px;height: 27px;background-color: #004085;outline: none;border: 0;color: #fff;cursor: pointer;border-radius: 5px;}.plus p {text-align: center;}a {text-decoration: none;color: #004085;font-weight: 600;}.myDate {color: #004085;}.plus h1 { text-align: center; color: #333; margin: 20px 0; font-size: 20px; } .show h1 { text-align: center; color: #333; margin: 20px 0; } table { margin: 0 auto; width: 850px; border-collapse: collapse; color: #004085; } th { padding: 10px; background: #cfe5ff; font-size: 20px; font-weight: 400; } td, th { border: 1px solid #b8daff; } td { padding: 10px; color: #666; text-align: center; font-size: 16px; } tbody tr { background: #fff; } tbody tr:hover { background: #e1ecf8; } .info { width: 400px; margin: 30px auto; text-align: center; } .info input, .info select { width: 80px; height: 27px; outline: none; border-radius: 5px; border: 1px solid #b8daff; padding-left: 5px; box-sizing: border-box; margin-right: 15px; } .info button { width: 60px; height: 27px; background-color: #004085; outline: none; border: 0; color: #fff; cursor: pointer; border-radius: 5px; } .plus p { text-align: center; } a { text-decoration: none; color: #004085; font-weight: 600; } .myDate { color: #004085; }.plus h1 { text-align: center; color: #333; margin: 20px 0; font-size: 20px; } .show h1 { text-align: center; color: #333; margin: 20px 0; } table { margin: 0 auto; width: 850px; border-collapse: collapse; color: #004085; } th { padding: 10px; background: #cfe5ff; font-size: 20px; font-weight: 400; } td, th { border: 1px solid #b8daff; } td { padding: 10px; color: #666; text-align: center; font-size: 16px; } tbody tr { background: #fff; } tbody tr:hover { background: #e1ecf8; } .info { width: 400px; margin: 30px auto; text-align: center; } .info input, .info select { width: 80px; height: 27px; outline: none; border-radius: 5px; border: 1px solid #b8daff; padding-left: 5px; box-sizing: border-box; margin-right: 15px; } .info button { width: 60px; height: 27px; background-color: #004085; outline: none; border: 0; color: #fff; cursor: pointer; border-radius: 5px; } .plus p { text-align: center; } a { text-decoration: none; color: #004085; font-weight: 600; } .myDate { color: #004085; }
完成css部分后,页面效果如图,是不是变得美观了很多呢~
完成html和css代码后,我们得到了一个(比较)漂亮的空壳子。为了让这个空壳子具有实际的功能,我们还需要完成js代码~
3.js部分
重头戏来咯~让我们来一起分析各个模块的需求及实现思路。
本项目是将数据作为对象,存储在数组arr中,并及时在该数组发生变化时,更新到本地仓库localStorage中。arr数组是一个全局变量,我们在增、删、标记数据时,都是对arr数组中的数据进行处理。处理过后,根据数组中数据,实时渲染到网页中。
数组中的数据有三条属性值:uname(任务名),udate(截止时间),state(该任务是否被勾选完成?是的话为true,否则为false)。
const obj = {uname: uname.value,//表单录入的任务名udate: ddl,//根据udate.value计算得出ddlstate: false//该任务是否被勾选}const obj = { uname: uname.value,//表单录入的任务名 udate: ddl,//根据udate.value计算得出ddl state: false//该任务是否被勾选 }const obj = { uname: uname.value,//表单录入的任务名 udate: ddl,//根据udate.value计算得出ddl state: false//该任务是否被勾选 }
(1)任务清单渲染模块:
什么时候需要渲染任务清单呢?当然是任务清单上的条目发生变化时咯~因此我们需要封装一个渲染函数render(),以便在页面刚加载完成时、新增任务条目、删除任务条目时调用。
渲染思路:
- 1.获取本地数据,转换为对象数组,存入arr。之后的渲染都是从arr中读取对象。
- 2.函数最开始需要清空页面以前渲染的内容,避免一条数据重复打印
- 3.利用循环,逐条生成tr,用模版字符串填入内容,再追加到tbody中
- 4.渲染完一条数据后,查看其state属性。如果为true,则用js将对应的字体属性修改为“划去”
- 5.所有数据渲染完成后,判断是否每个对象的state都为true。如果是,将‘全选’勾上。
- 6.函数封装完成后要调用一次。这样每次页面重新加载后都会显示本地存储的数据了。
- 代码如下:
//获取元素const p = document.querySelector('p')const tbody = document.querySelector('tbody')const uname = document.querySelector('.uname')const udate = document.querySelector('.udate')// console.log(uname);// console.log(udate);const items = document.querySelectorAll('[name]')//读取本地数据const data = localStorage.getItem('myData')//存入arr数组中,如果没有本地数据则为空数组const arr = data ? JSON.parse(data) : []const info = document.querySelector('.info')//封装渲染函数function render() {//清空以前的避免重复打印tbody.innerHTML = ''let flag = true//代表全选被勾选for (let i = 0; i < arr.length; i++) {//生成trconst tr = document.createElement('tr')//用模版字符串填充tr.innerHTML = `<td><input type="checkbox" class="ck"></td><td>${arr[i].uname}</td><td>${arr[i].udate}</td><td><a href="javascript:" data-id=${i}>删除</a></td>`//追加到页面中tbody.appendChild(tr)//每一个删除键都设置了对应的data-id,以便后期点击时找到对应数据删除const a = tr.querySelector('a')console.log(a.dataset.id);//根据state修改勾选框的状态const input = tr.querySelector('input')input.checked = arr[i].state//根据state修改字体样式if (arr[i].state) {const td = tr.querySelector('td:nth-of-type(2)')// console.log(td);td.style.textDecoration = 'line-through'const td2 = td.nextElementSiblingtd2.style.textDecoration = 'line-through'const td3 = td2.nextElementSiblingtd3.style.textDecoration = 'line-through'}else {flag = false//任意一个对象state=false则全选标记置为false}}//修改全选框document.querySelector('#checkAll').checked = flag}//别忘了调用render()//获取元素 const p = document.querySelector('p') const tbody = document.querySelector('tbody') const uname = document.querySelector('.uname') const udate = document.querySelector('.udate') // console.log(uname); // console.log(udate); const items = document.querySelectorAll('[name]') //读取本地数据 const data = localStorage.getItem('myData') //存入arr数组中,如果没有本地数据则为空数组 const arr = data ? JSON.parse(data) : [] const info = document.querySelector('.info') //封装渲染函数 function render() { //清空以前的避免重复打印 tbody.innerHTML = '' let flag = true//代表全选被勾选 for (let i = 0; i < arr.length; i++) { //生成tr const tr = document.createElement('tr') //用模版字符串填充 tr.innerHTML = ` <td><input type="checkbox" class="ck"></td> <td>${arr[i].uname}</td> <td>${arr[i].udate}</td> <td> <a href="javascript:" data-id=${i}>删除</a> </td> ` //追加到页面中 tbody.appendChild(tr) //每一个删除键都设置了对应的data-id,以便后期点击时找到对应数据删除 const a = tr.querySelector('a') console.log(a.dataset.id); //根据state修改勾选框的状态 const input = tr.querySelector('input') input.checked = arr[i].state //根据state修改字体样式 if (arr[i].state) { const td = tr.querySelector('td:nth-of-type(2)') // console.log(td); td.style.textDecoration = 'line-through' const td2 = td.nextElementSibling td2.style.textDecoration = 'line-through' const td3 = td2.nextElementSibling td3.style.textDecoration = 'line-through' } else { flag = false//任意一个对象state=false则全选标记置为false } } //修改全选框 document.querySelector('#checkAll').checked = flag } //别忘了调用 render()//获取元素 const p = document.querySelector('p') const tbody = document.querySelector('tbody') const uname = document.querySelector('.uname') const udate = document.querySelector('.udate') // console.log(uname); // console.log(udate); const items = document.querySelectorAll('[name]') //读取本地数据 const data = localStorage.getItem('myData') //存入arr数组中,如果没有本地数据则为空数组 const arr = data ? JSON.parse(data) : [] const info = document.querySelector('.info') //封装渲染函数 function render() { //清空以前的避免重复打印 tbody.innerHTML = '' let flag = true//代表全选被勾选 for (let i = 0; i < arr.length; i++) { //生成tr const tr = document.createElement('tr') //用模版字符串填充 tr.innerHTML = ` <td><input type="checkbox" class="ck"></td> <td>${arr[i].uname}</td> <td>${arr[i].udate}</td> <td> <a href="javascript:" data-id=${i}>删除</a> </td> ` //追加到页面中 tbody.appendChild(tr) //每一个删除键都设置了对应的data-id,以便后期点击时找到对应数据删除 const a = tr.querySelector('a') console.log(a.dataset.id); //根据state修改勾选框的状态 const input = tr.querySelector('input') input.checked = arr[i].state //根据state修改字体样式 if (arr[i].state) { const td = tr.querySelector('td:nth-of-type(2)') // console.log(td); td.style.textDecoration = 'line-through' const td2 = td.nextElementSibling td2.style.textDecoration = 'line-through' const td3 = td2.nextElementSibling td3.style.textDecoration = 'line-through' } else { flag = false//任意一个对象state=false则全选标记置为false } } //修改全选框 document.querySelector('#checkAll').checked = flag } //别忘了调用 render()
(2)任务完成勾选模块
该模块由两个函数组成:
- 1、revise函数:在复选框发生点击事件时调用,可以根据任务清单中对应的复选框勾选情况,来修改arr[i]的state值,并更新到本地存储里。同时更改字体样式:勾选则划掉文字,未勾选则更改为不划掉。
//修改属性函数function revise(i, cks) {//更改arr的state属性arr[i].state = cks[i].checked ? true : false// console.log(arr[i]);//更新本地存储localStorage.setItem('myData', JSON.stringify(arr))// console.log(arr[i].state);//修改样式:划掉还是不划掉?const trs = document.querySelectorAll('tr')console.log(trs[1]);const td = trs[i + 1].querySelector('td:nth-of-type(2)')if (arr[i].state) {// console.log('我要划掉了');// console.log(td);td.style.textDecoration = 'line-through'const td2 = td.nextElementSiblingtd2.style.textDecoration = 'line-through'const td3 = td2.nextElementSiblingtd3.style.textDecoration = 'line-through'}else {td.style.textDecoration = 'none'const td2 = td.nextElementSiblingtd2.style.textDecoration = 'none'const td3 = td2.nextElementSiblingtd3.style.textDecoration = 'none'}}//修改属性函数 function revise(i, cks) { //更改arr的state属性 arr[i].state = cks[i].checked ? true : false // console.log(arr[i]); //更新本地存储 localStorage.setItem('myData', JSON.stringify(arr)) // console.log(arr[i].state); //修改样式:划掉还是不划掉? const trs = document.querySelectorAll('tr') console.log(trs[1]); const td = trs[i + 1].querySelector('td:nth-of-type(2)') if (arr[i].state) { // console.log('我要划掉了'); // console.log(td); td.style.textDecoration = 'line-through' const td2 = td.nextElementSibling td2.style.textDecoration = 'line-through' const td3 = td2.nextElementSibling td3.style.textDecoration = 'line-through' } else { td.style.textDecoration = 'none' const td2 = td.nextElementSibling td2.style.textDecoration = 'none' const td3 = td2.nextElementSibling td3.style.textDecoration = 'none' } }//修改属性函数 function revise(i, cks) { //更改arr的state属性 arr[i].state = cks[i].checked ? true : false // console.log(arr[i]); //更新本地存储 localStorage.setItem('myData', JSON.stringify(arr)) // console.log(arr[i].state); //修改样式:划掉还是不划掉? const trs = document.querySelectorAll('tr') console.log(trs[1]); const td = trs[i + 1].querySelector('td:nth-of-type(2)') if (arr[i].state) { // console.log('我要划掉了'); // console.log(td); td.style.textDecoration = 'line-through' const td2 = td.nextElementSibling td2.style.textDecoration = 'line-through' const td3 = td2.nextElementSibling td3.style.textDecoration = 'line-through' } else { td.style.textDecoration = 'none' const td2 = td.nextElementSibling td2.style.textDecoration = 'none' const td3 = td2.nextElementSibling td3.style.textDecoration = 'none' } }
- 2.checkbox函数:用于在复选框发生点击事件时调用。如果点击了全选框,就将每个小复选框的状态更新为全选框的状态,并调用revise来更改样式和存储数据;如果点击了其他普通复选框,就调用revise来更改样式和存储数据,同时检查是否需要更新全选框勾选状态。
- 因为checkbox函数给复选框和全选框注册了点击事件,所以也要调用一下。在全局范围内调用一次就可以把需要的点击事件都注册上了~代码如下:
function checkbox() {const checkAll = document.querySelector('#checkAll')const cks = document.querySelectorAll('.ck')// console.log(checkAll);// console.log(cks);checkAll.addEventListener('click', function () {for (let i = 0; i < cks.length; i++) {cks[i].checked = this.checked//修改属性// console.log(cks[i].checked);revise(i, cks)}})for (let i = 0; i < cks.length; i++) {cks[i].addEventListener('click', function () {revise(i, cks)checkAll.checked = document.querySelectorAll('.ck:checked').length === cks.length})}}checkbox()function checkbox() { const checkAll = document.querySelector('#checkAll') const cks = document.querySelectorAll('.ck') // console.log(checkAll); // console.log(cks); checkAll.addEventListener('click', function () { for (let i = 0; i < cks.length; i++) { cks[i].checked = this.checked //修改属性 // console.log(cks[i].checked); revise(i, cks) } }) for (let i = 0; i < cks.length; i++) { cks[i].addEventListener('click', function () { revise(i, cks) checkAll.checked = document.querySelectorAll('.ck:checked').length === cks.length }) } } checkbox()function checkbox() { const checkAll = document.querySelector('#checkAll') const cks = document.querySelectorAll('.ck') // console.log(checkAll); // console.log(cks); checkAll.addEventListener('click', function () { for (let i = 0; i < cks.length; i++) { cks[i].checked = this.checked //修改属性 // console.log(cks[i].checked); revise(i, cks) } }) for (let i = 0; i < cks.length; i++) { cks[i].addEventListener('click', function () { revise(i, cks) checkAll.checked = document.querySelectorAll('.ck:checked').length === cks.length }) } } checkbox()
(3)实时日期渲染模块
这部分调用了定时函数,来实时更新时间显示模块中的文字内容,比较简单,只要熟悉日期对象Date和定时函数setInterval就可以啦~
function getWeek(a) {const arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']return arr[a % 7]}setInterval(function () {const date = new Date()p.innerHTML = ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`}, 1000)function getWeek(a) { const arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'] return arr[a % 7] } setInterval(function () { const date = new Date() p.innerHTML = ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}` }, 1000)function getWeek(a) { const arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'] return arr[a % 7] } setInterval(function () { const date = new Date() p.innerHTML = ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}` }, 1000)
(4)表单录入模块
该模块负责在点击“录入”按钮时,将表单中的内容经过处理后存储到本地,并调用render()重新渲染任务清单。
- 1.录入的时候会根据下拉表单选择的时间来计算ddl。这里封装了一个计算时间的函数。该函数可以传入当前的时间戳以及要经过的时间(ms),计算出截止时间。如下所示:
function culTime(now, period) {const ddl = now + periodconst date = new Date(ddl)return ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}点`}// const now = +new Date()// console.log(culTime(now, 21600000));function culTime(now, period) { const ddl = now + period const date = new Date(ddl) return ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}点` } // const now = +new Date() // console.log(culTime(now, 21600000));function culTime(now, period) { const ddl = now + period const date = new Date(ddl) return ` ${getWeek(date.getDay())} ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}点` } // const now = +new Date() // console.log(culTime(now, 21600000));
- 2.注册表单提交事件:首先要阻止提交后自动跳转的默认事件,再读取表单中的数据,处理后写入一个新对象里,再把该对象push进arr数组,再存入localStorage就可以了。
- 注意创建对象前要验证表单内容是否为空,空的话要return。
- 注意提交后要清空表单内容
- 注意要调用checkbox()函数。因为增加了新的复选框,这些新的复选框也需要用checkbox()注册点击事件,不然会出bug的!
//录入模块info.addEventListener('submit', function (e) {//阻止默认跳转e.preventDefault()cks = document.querySelectorAll('.ck')//表单验证for (let i = 0; i < items.length; i++) {if (items[i].value == '') {return alert('输入内容不能为空')}}//获取当前时间戳const now = +new Date()let ddl = ''//调用时间计算函数来计算ddl的值switch (udate.value) {case '六小时'://21600000ddl = culTime(now, 21600000)breakcase '一天'://86400000ddl = culTime(now, 86400000)breakcase '两天'://172800000ddl = culTime(now, 172800000)breakcase '三天'://259200000ddl = culTime(now, 259200000)breakcase '一星期':// 604800000ddl = culTime(now, 604800000)break}console.log(ddl);//存入arr和本地const obj = {uname: uname.value,udate: ddl,state: false}//console.log(obj);arr.push(obj)localStorage.setItem('myData', JSON.stringify(arr))//console.log(JSON.parse(localStorage.getItem('myData')));//清空表单中内容this.reset()//渲染render()//重新注册一下事件checkbox()})//录入模块 info.addEventListener('submit', function (e) { //阻止默认跳转 e.preventDefault() cks = document.querySelectorAll('.ck') //表单验证 for (let i = 0; i < items.length; i++) { if (items[i].value == '') { return alert('输入内容不能为空') } } //获取当前时间戳 const now = +new Date() let ddl = '' //调用时间计算函数来计算ddl的值 switch (udate.value) { case '六小时'://21600000 ddl = culTime(now, 21600000) break case '一天'://86400000 ddl = culTime(now, 86400000) break case '两天'://172800000 ddl = culTime(now, 172800000) break case '三天'://259200000 ddl = culTime(now, 259200000) break case '一星期':// 604800000 ddl = culTime(now, 604800000) break } console.log(ddl); //存入arr和本地 const obj = { uname: uname.value, udate: ddl, state: false } //console.log(obj); arr.push(obj) localStorage.setItem('myData', JSON.stringify(arr)) //console.log(JSON.parse(localStorage.getItem('myData'))); //清空表单中内容 this.reset() //渲染 render() //重新注册一下事件 checkbox() })//录入模块 info.addEventListener('submit', function (e) { //阻止默认跳转 e.preventDefault() cks = document.querySelectorAll('.ck') //表单验证 for (let i = 0; i < items.length; i++) { if (items[i].value == '') { return alert('输入内容不能为空') } } //获取当前时间戳 const now = +new Date() let ddl = '' //调用时间计算函数来计算ddl的值 switch (udate.value) { case '六小时'://21600000 ddl = culTime(now, 21600000) break case '一天'://86400000 ddl = culTime(now, 86400000) break case '两天'://172800000 ddl = culTime(now, 172800000) break case '三天'://259200000 ddl = culTime(now, 259200000) break case '一星期':// 604800000 ddl = culTime(now, 604800000) break } console.log(ddl); //存入arr和本地 const obj = { uname: uname.value, udate: ddl, state: false } //console.log(obj); arr.push(obj) localStorage.setItem('myData', JSON.stringify(arr)) //console.log(JSON.parse(localStorage.getItem('myData'))); //清空表单中内容 this.reset() //渲染 render() //重新注册一下事件 checkbox() })
(5)删除操作模块
采取事件委托,给删除的‘父亲’tbody注册点击事件。通过data-id属性能拿到相应的数据在arr中的下标号,将该条数据删除并更新到本地仓库即可。
- 其中也要调用checkbox()函数,因为删除时复选框的序列号发生变化,需要更新状态。
//删除操作和勾选操作tbody.addEventListener('click', function (e) {console.log(e.target);if (e.target.tagName == 'A') {arr.splice(e.target.dataset.id, 1)localStorage.setItem('myData', JSON.stringify(arr))render()checkbox()}})//删除操作和勾选操作 tbody.addEventListener('click', function (e) { console.log(e.target); if (e.target.tagName == 'A') { arr.splice(e.target.dataset.id, 1) localStorage.setItem('myData', JSON.stringify(arr)) render() checkbox() } })//删除操作和勾选操作 tbody.addEventListener('click', function (e) { console.log(e.target); if (e.target.tagName == 'A') { arr.splice(e.target.dataset.id, 1) localStorage.setItem('myData', JSON.stringify(arr)) render() checkbox() } })
三、总结
综上,将html,css,js代码放入他们该在的位置,我们的代码就全部完成了~获得了一个可以在日常生活中使用的任务列表,且数据存储在本地不会丢失(除非你手动删了)。笔者是个前端小白,独立完成此项目后感觉对代码的理解能力上升了,也注意到了一些以前没发现的点:
- 项目中要实时关注全局变量的状态,例如arr和document.ququerySelectorAll拿到的对象。假如我一开始将所有复选框存入了ck变量中,但是当数据新增或删除后,复选框就发生了改变,需要更新ck!不然就会出现奇怪的bug半天无法解决…..
- 本项目代码量差不多四百行,写的时候要思路清晰,先分析需求,写好大纲!不要写一布看一步,不然效率会很低下…..
- 代码永远都有可以简化的空间,继续学习更多的知识,回头再来看今天的任务,一定可以写出更高效简洁的代码的!