使用js实现一个任务管理列表|青训营

使用js写了一个任务管理列表,数据存储在本地,可以实现:自动计算任务完成时间、标记完成、录入、删除任务。主要是练习和熟悉一些DOM操作~而且日常记录任务也可以使用这个自己设计的网页,成就感upup!

实现效果如下图所示~

image.png
接下来就来跟我一起定制自己专属的任务列表吧~

一、代码结构

1.html部分

用html搭建一个简单的骨架,包括标题、实时时间显示模块、任务录入模块、任务清单的标题部分。

2.css部分

用css实现两个大盒子在屏幕上的布局,再设置相应的字体、边框等样式。

3.js部分

前面两个部分的代码都非常简单。js才是实现本项目的重头戏。js部分包括以下几个模块:
(1)任务清单渲染模块

(2)任务完成勾选模块

(3)实时日期渲染模块

(4)表单录入模块

(5)删除操作模块

接下来跟着我完善各部分代码吧~

二、代码实现

1.html部分

分为两个大盒子:plus盒子用于新增任务,show盒子用于展示清单。

按照预想的架构,把标题和文本框,下拉表单,按钮,任务列表的骨架一个个摆上去就好了。

完成后的效果如图:

image.png
以下为源码:

<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部分后,页面效果如图,是不是变得美观了很多呢~

image.png

完成html和css代码后,我们得到了一个(比较)漂亮的空壳子。为了让这个空壳子具有实际的功能,我们还需要完成js代码~

3.js部分

重头戏来咯~让我们来一起分析各个模块的需求及实现思路。

本项目是将数据作为对象,存储在数组arr中,并及时在该数组发生变化时,更新到本地仓库localStorage中。arr数组是一个全局变量,我们在增、删、标记数据时,都是对arr数组中的数据进行处理。处理过后,根据数组中数据,实时渲染到网页中。

数组中的数据有三条属性值:uname(任务名),udate(截止时间),state(该任务是否被勾选完成?是的话为true,否则为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//该任务是否被勾选
            }
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++) {
//生成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()
//获取元素 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.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'
            }



        }
//修改属性函数 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 + 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));
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 '六小时'://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()

        })
//录入模块 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代码放入他们该在的位置,我们的代码就全部完成了~获得了一个可以在日常生活中使用的任务列表,且数据存储在本地不会丢失(除非你手动删了)。笔者是个前端小白,独立完成此项目后感觉对代码的理解能力上升了,也注意到了一些以前没发现的点:

  1. 项目中要实时关注全局变量的状态,例如arr和document.ququerySelectorAll拿到的对象。假如我一开始将所有复选框存入了ck变量中,但是当数据新增或删除后,复选框就发生了改变,需要更新ck!不然就会出现奇怪的bug半天无法解决…..
  2. 本项目代码量差不多四百行,写的时候要思路清晰,先分析需求,写好大纲!不要写一布看一步,不然效率会很低下…..
  3. 代码永远都有可以简化的空间,继续学习更多的知识,回头再来看今天的任务,一定可以写出更高效简洁的代码的!

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYVHLxyF' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片