来做一个简单的 To-do List 吧! (上)

前言

今天来尝试做个简单版的 To-do List,让自己对於 To-do List 的实作有一个粗略的概念,以下会先叙述实作流程,再一步步完成。

那就开始罗~

实作流程

因为主要功能包含新增,删除和勾选完成,区域又分成待办事项区和已完成事项区,所以上篇会先针对待办事项区的功能实作,下篇再继续实作已完成事项区的功能。

HTML结构

  • HTML的结构分成三个部分,可以比对图片和 HTML 的结构会比较清楚

// 整个待办事项表单
<div class="todo">
    // 1. 可以输入事项的区域
    <header>
      <h4>待办事项</h4>
      <div class="form">
        <input type="text" placeholder="add todos" class="newTodo">
        <button class="btn addButton">新增</button>
      </div>
    </header>
    
    // 2. 显示待办事项的区域
    <ul class="pending">
      <!-- 放待办事项新增区域 -->
    </ul>
    
    // 3. 显示已完成事项的区域
    <h4>完成事项</h4>
    <ul class="done">
      <!-- 放完成事项区域 -->
    </ul>
</div>

新增

以下是会需要监听的元素,先用querySelector()方法选出来并存到变数中

// 选取元素
let pending = document.querySelector('.pending') // 会放入使用者输入内容的容器
let addButton = document.querySelector('.addButton') // 新增按钮
let input = document.querySelector('.newTodo') //输入框
let done = document.querySelector('.done') // 完成区域

对於节点的新增、删除还没有概念的朋友推荐先看看这篇 走!去浏览器用 create & append 加餐,有超级可爱的饼乾怪,看完保证一定学会节点的操作~~~

  1. 首先做新增的函式,这个函式里头先建立一个li的元素
  2. 利用样板字面值(template literal)赋予该元素的内容
  3. 利用appendChild()方法,将节点加入到容器pending的末端
function addTodo (text) {
  const newTodo = document.createElement('li')
  
  newTodo.innerHTML = `
    <input value ="${text}">
    <div class="icon-group">
      <i class="delete fa fa-trash"></i>
      <i class="check fa fa-check-circle"></i>
    </div>
  `
  pending.appendChild(newTodo)
}
  1. 监听新增按钮,如果点击就把输入的内容传入addTodo函式中,就会新增一笔待办事项
addButton.addEventListener("click", function () {
  const inputValue = input.value
  if (inputValue.trim().length > 0) {
    addTodo(inputValue)
  }
})

用假资料确认功能

为了确认addTodo的函式能正常运作,可以先用假资料试试看~
这部分确认成功就可以删除,如果要一开始显示预设的资料可以保留没关系

const todos = ['写今天的铁人赛文章', '写明天的铁人赛文章', '写後天的铁人赛文章']

function displayDummyData(todos) {
  for (let todo of todos) {
      addTodo(todo)
  }
}

displayDummyData(todos);

勾选完成及删除

由於我觉得勾选完成和删除的行为是状态的改变(可能是从未完成到已完成,或是被使用者删除,感觉有点像Promise XD),所以用一个changeState的函式封装

  1. closest()向上找到li元素

closest()里头的参数放CSS选取器,会向上一直往根节点查找指定的元素,如果找到根节点都没有指定的元素,则传回 null值

  1. 如果点击目标是垃圾桶图形,就将该笔事项移除
  2. 如果点击目标是打勾勾图形,就将该笔事项删除,并再建立新的li放入已完成区域
  3. pending aka 待办事项区绑定监听器,如果触发就执行changeState函式

function changeState (e) {
  const list = e.target.closest('li')
  
  if (e.target.classList.contains('delete')) {
    list.remove();
  } 
  else if (e.target.classList.contains('check')) { 
    list.remove()   
    const itemDone = document.createElement('li')
    const content = list.children[0].value
    itemDone.innerHTML += `<input value ="${content}" class="checked" disabled="disabled">
    <div class="icon-group">
      <i class="delete fa fa-trash"></i>
      <i class="check fa fa-check-circle"></i>
    </div>`
      
    done.appendChild(itemDone)
  }
}

pending.addEventListener('click', changeState)

小结:

在实作过程中体会到对於节点位置的关系越清晰才不会一直选错节点,如果发生鬼打墙现象建议直接console.log(),看看自己是不是明明想选苹果却选到奇异果/images/emoticon/emoticon37.gif

明天再来实作已完成事项区的部分罗~

参考资料:

实作一个简单的 Todolist (上)
MDN - Element.children
JavaScript大全


<<:  大共享时代系列_024_可协同 UI 设计的软件

>>:  Day25 每年都在烦恼要送什麽礼物给亲朋好友吗?何不送个AR明信片呢!?

Day 0 [PV]: 原生 vs 跨平台框架

哇哇哇,挑战第一天我就没准备好,只能很赶的生出一篇文章。 不负责任预告一下:我中文不是很好所以要是文...

(笔记D1) Spring MVC 框架

1-1 Spring MVC 特质 功能建构在 Servlet、JSP 规格基础上面发展,必须透过 ...

[Day 26] - React 前端串後端 - 串接登入

经过一整天的奋斗,终於跟React稍微熟了一点 首先建一个apiUtil.js 我打算把跟後端相关的...

Data layer testing (3)

上一篇我们写好了 EtaResponseMapper 的 unit test。但 data laye...

Python -今天我想来点爬虫程序

爬虫原理: 抓取资料->分析结构->取出要的结构文字->输出想要的格式 程序码: ...