Skip to content

Latest commit

 

History

History
210 lines (157 loc) · 7.26 KB

week7_todolist 實作練習.md

File metadata and controls

210 lines (157 loc) · 7.26 KB
tags: JavaScript

【學習筆記】利用 JavaScript 實作簡易 Todo List

本篇為 [FE102] 前端必備:JavaScript 這門課程的學習筆記。如有錯誤歡迎指正。

前言

久久未更新,自從加入程師導師計畫後,不知不覺持續寫程式也快滿三個月了。這禮拜進入第二次複習週,雖然仍有許多進度要補上,回頭複習也同樣重要!

於是趁這週把之前實作過的 Todo List 觀念再重整一次,除了練習如何透過 JavaScript 操控 DOM 元素、如何進行事件監聽,寫下這篇筆記做記錄。

目標功能

  • 新增 todo
  • 刪除 todo
  • 標記 todo 為已完成/未完成
  • 延伸:搭配 localStorage 本地儲存

Step1. 分析網頁所需元素

在開始切版前,可利用 whimsical 等工具先畫出設計稿:

  • wrapper:包含整個 Todo List 的容器
  • .todo__input:輸入欄位 input 和新增按鈕
  • .todo__list:放置所有 todo 的容器
  • .todo:切換狀態 checkbox、todo 標題、刪除按紐

Step2. 開始切版

按照設計稿,寫出程式碼如下:

<div class="wrapper">
  <h1>Todo List</h1>
  <div class="todo__input-block">
    <input class="todo__input" type="text" placeholder="Add New Todo Here..." minlength="1" maxlength="48">
    <button class="btn-new"></button>
  </div>
  <div class="todo__hr"></div>

  <ul class="todo__list">
    <li class="todo">
      <label class="todo__title">
        <input class="todo__check" type="checkbox">
        <p>Fix debug</p>
      </label>
      <button class="btn-delete"></button>
    </li>
    <li class="todo">
      <label class="todo__title">
        <input class="todo__check" type="checkbox">
        <p>Write code</p>
      </label>
      <button class="btn-delete"></button>
    </li>
  </ul>
</div>

<label> 標籤中放入 input 標籤,就不需指定 for 和 id,可參考:HTML <label> 标签的 for 属性

將上述程式碼再加入 css 屬性,排版後版面如下:

Step3. 建立監聽事件

在處理事件時,通常會需要指派監聽者(Event listeners)來監聽事件觸發。

透過監測 DOM 中的某一元素(element),當使用者觸發某事件(event)時,就會執行後續動作(functuion),語法如下:

element.addEventListener('event', function, useCapture)
  • event 事件:監聽事件類型,如:clickkeypress
  • function 功能:當指定事件觸發時執行函式
  • useCapture:指定事件在捕獲或冒泡階段執行,預設值為 flase(冒泡)

參考資料:[week 7] DOM 事件傳遞機制:捕獲與冒泡、事件代理

新增 todo

  • 在輸入框 點選 Add / 按下 Enter 鍵,可新增 todo
  • 新增後清空輸入框內容

步驟如下:

  1. 選取需要的 DOM 元素,監聽該元素的 click / keypress 事件
// 點擊按鈕新增
document.querySelector('.btn-new').addEventListener('click', function () {
  addTodos();
});

// 按 Enter 新增
document.querySelector('.todo__input').addEventListener('keypress', function (e) {
  // Enter 對應鍵盤代碼:13
  if (e.which === 13) {
    addTodos();
  }
});
  1. 若接收到事件,以函式 addTodos 處理新增 todo
function addTodos() {
  const inputValue = document.querySelector('.todo__input').value;
  
 // 檢查輸入欄位是否為空值,trim() 可清除字串前後空白
  if (inputValue.trim().length === 0) return;
  // 新增 todo
  const newTodo = document.createElement('li');
  newTodo.classList.add('todo');
  newTodo.innerHTML = `
    <label class="todo__title">
      <input class="todo__check" type="checkbox">
      <p>${escapeHtml(inputValue)}</p>
    </label>
    <button class="btn-delete"></button>
  `
  document.querySelector('.todo__list').appendChild(newTodo);
  // 新增成功後,清空輸入欄
  document.querySelector('.todo__input').value = '';
}
  1. 利用跳脫函式 escapeHtml 處理特殊字元,防止程式碼無法正常顯示
function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

刪除 todo

  • 點擊右側叉叉圖示,可刪除 todo

遇到問題:動態新增

由於 todo 是「動態新增」,若直接選取 btn-delete,將無法對後來新增的按鈕進行監聽。

解決辦法:事件代理

我們可透過事件傳遞機制,改成對父元素(事件代理)進行事件監聽,如此即可對底下的所有 btn-delete 進行監聽。

// 事件代理:透過父元素來監聽 click 事件
document.querySelector('.todo__list').addEventListener('click', function (event) {
  const target = event.target;
  // 刪除 todo
  if (target.classList.contains('btn-delete')) {
    target.parentNode.remove()
  }
});

標記 todo 為已完成/未完成

  • 點擊左側框框,能夠切換狀態為 已完成 / 未完成

步驟如下:

  1. 同樣監聽 checkbox 的父元素 .todo__list
  2. 若點擊目標包含 checkbox,即可切換狀態
document.querySelector('.todo__list').addEventListener('click', function (event) {
  const target = event.target;
  // check / uncheck todo
  if (target.classList.contains('todo__check')) {
    target.parentNode.classList.toggle('todo__done')
  }
}

延伸:搭配 localStorage 本地儲存

localStorage

  • 是由 HTML5 提供的一種 Web Storage
  • 儲存大小約 5MB
  • 可將資料儲存在用戶端,資料就不會因重整頁面或關閉瀏覽器而消失
  • 以 key-value pair 的形式保存,且會轉成 JSON 字串格式

localStorage method

  • 儲存資料:localStorage.setItem('key', 'value')
  • 讀取資料:let storageValue = localStorage.getItem(key, - value)
  • 清除資料:localStorage.removeItem(key)
  • 清除全部資料:localStorage.clear()

搭配 localStorage 實作 Todo List,我們可將資料存放在瀏覽器。但似乎還需要時間來研究如何使用,等之後熟悉用法會再來更新!

參考內容:

  1. [JS初心者]帶你用localStorage做出一個陽春版「To-Do List」(待辦清單)-1
  2. Day 20 - 30 天 Progressive Web App 學習筆記 - To-Do List 實作 PWA - (新增/修改/刪除待辦事項清單)
  3. JS30-Day15-LocalStorage
  4. HTML5 Web Storage
  5. [JavaScript] Cookie、LocalStorage、SessionStorage 三種差異