最终章:Todo List实作

前面提到了物件、阵列、DOM元素的选取、事件监听,以及最後的localStorage。这些足够我们用JavaScript做一个小小的网页程序,来验证一下之前提到的方法。

这次我们要来做的是Todo List。

假设金庸先生要邀请武林高手来参加华山论剑,要邀请的人太多了,他记性不好,所以写了一个小程序来记录与会者名单。大概是长这个样子。

然後在来拆解画面上的功能:

我们可已先把上面的的那张图区分为三种程序区块:

  • 事件:
    • 加入邀请名单:点击,使用者输入的资料加入「邀请名单」的localStorage,并渲染到画面
    • 寄出:将资料从「邀请名单」的localStorage中移除,加入已寄出名单的localStorage,并渲染到画面
    • 移除:将资料由「已寄出名单」的localStorage中移除,并渲染到画面
  • 资料:
    • 邀请名单的localStorage资料
    • 寄出名单的localStorage资料
  • 画面:将localStorage的资料渲染到网页

所以我们就可以开始实作了!

画面上的HTML码如下:

<div class="content">

  <div class="logo">
    <img src="https://imgur.com/uEvCO7p.png" width="150px" alt="">
    <div class="logotext">TODO LIST</div>
  </div>

  <div class="addList">
    <input type="text" size="30" class="text" placeholder="请输入与会者姓名" required>
    <button type="button" class="send">新增邀请名单</button>
  </div>

</div>

<div class="item">
  <h3>计画邀请<span class="noneNum"></span>人</h3>
  <ul class="list">

  </ul>
</div>

<div class="finishedItem">
  <h3>已邀请<span class="doneNum"></span>人</h3>
  <ul id="finishlist">

  </ul>
</div>

进入JavaScript的部分,先把DOM元素选取起来:

//指定DOM
let send = document.querySelector('.send');
let list = document.querySelector('.list');
let finishList = document.getElementById('finishlist');

接下来定义资料的部分:

  • 计画邀请的名单,要把它变成阵列物件的格式
  • 已经寄出邀请函的名单,也要转成阵列物件的格式
//资料:设定计画邀请名单「listData」的localStorage资料,转为阵列物件
let data = JSON.parse(localStorage.getItem('listData')) || [];

//资料:设定寄出名单「listFinish」的localStorage资料,转为阵列物件
let finishData = JSON.parse(localStorage.getItem('listFinish')) || [];

接下来把事件绑订到前面指定的DOM元素上。然後更新资料,此时尚未输入资料,localStorage的key应该还没建立,所以为空阵列。

//事件绑定,监听与更新
send.addEventListener('click', addData);
list.addEventListener('click', toggleDone);
finishList.addEventListener('click', deleDone);

//更新画面上的资料
updateList(data);
updateFinish(finishData);

按下「新增邀请名单後」把资料新增到data中,并叫用updateList这个函式,把资料组字串,渲染到画面中。

//按下「新增邀请名单後」,把资料新增到data中,并叫用updateList
function addData(e) {
    var txt = document.querySelector('.text');
    if (txt.value == "") {
        alert('必须输入与会者姓名');
        return;
    }
    var toInvite =
    {
        content: txt.value
    }

    data.push(toInvite);    
    updateList(data);
    localStorage.setItem('listData', JSON.stringify(data));
    txt.value = '';
}
//更新邀请清单
function updateList(items) {
    str = '';
    let len = items.length; 
		//for回圈组字串   
    for (let i = 0; len > i; i++) {
        console.log(items[i])
        str += `<li><a href="#" data-index=${i}>移到已邀请</a><span>${items[i].content}</span></li>`;
    }
    list.innerHTML = str;
    let noneNum = document.querySelector('.noneNum');
    noneNum.textContent = len;
}

按下「移到已邀请」时,执行以下程序区块:

//将与会者由邀请清单移至邀请函已寄出清单
function toggleDone(e){
		//避免事件冒泡
    e.preventDefault();
		//如果点选的不是a标签,那就不往下执行
    if(e.target.nodeName !== 'A'){
        return;
    }
    let index = e.target.dataset.index;
		//把点选的资料推送到finishData中
    finishData.push(data[index]);
		//清除计画邀请data中的资料
    data.splice(index,1);
		//更新计画邀请的名单
    localStorage.setItem('listData',JSON.stringify(data));
		//渲染网页
    updateList(data);
		//更新已寄出邀请函的名单
    localStorage.setItem('listFinish',JSON.stringify(finishData));
		//渲染网页
    updateFinish(finishData);
}

然後是渲染「已邀请名单」的部分:

//更新已寄邀请函清单
function updateFinish(finishItems){
    let mailStr = '';
    let len = finishItems.length;
    console.log(finishItems);
    console.log(len);
		//for回圈组字串 
    for(let i=0;i<len; i++){
        console.log(finishItems[i]);
        mailStr+= `<li><a href="#" data-num=${i}>移除</a><span>${finishItems[i].content}</span></li>`
    }
    finishList.innerHTML = mailStr;
    var doneNum = document.querySelector('.doneNum');
    doneNum.textContent = len;
}

如果点选「删除」,执行以下程序:

//删除已邀请的贵宾
function deleDone(e){
    e.preventDefault();
    if(e.target.nodeName !== 'A'){
        return;
    }
    let num = e.target.num;
		//清除计画邀请data中的资料
    finishData.splice(num,1);
		//更新已寄出邀请函的名单
    localStorage.setItem('listFinish',JSON.stringify(finishData));
		//渲染到网页
    updateFinish(finishData);
}

来看看我的实作吧!

https://codepen.io/popeye_ux/pen/KKqbMwq


<<:  好记性的浏览器:localStorage

>>:  Day 15 - UML x Interface — Notifier

焦虑与压力

前言 昨天分享了关於拒绝的两三事,是因为它容易出现在日常生活与团体协作当中,後续带来的影响也不容小觑...

用React刻自己的投资Dashboard Day6 - 建立图表区元件,串接API取得数据

tags: 2021铁人赛 React 上一篇使用静态的资料,将多张数据资料表画成线图呈现在网页上,...

如何在 WordPress 设定 Google reCAPTCHA 保护(登入、留言、联络)表单,免遭恶意攻击

在 WordPress 网站运行一段时间後,发现有恶意程序,一直在文章留言区发布广告贴文,一直手动删...

{DAY 14} NumPy 学习笔记(下)

前言 现在到了练习NumPy的最後一天,现在要开始跟资料分析的流程接轨 所以我决定从网路上的开源资...

Golang - Stack & Heap

常常在社群里面看到从其他程序语言转来用Go会有的问题 这些是找到的资料跟总结 同步更新在github...