iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
Modern Web

前端藏寶圖系列 第 25

來做一個簡單的 To-do List 吧! (上)

  • 分享至 

  • xImage
  •  

前言

今天來嘗試做個簡單版的 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大全


上一篇
來做一個色碼轉換器吧!
下一篇
來做一個簡單的 To-do List 吧!(下)
系列文
前端藏寶圖30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言