iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0

15 - LocalStorage

tags: JavaScript30

專案簡介

第十五天的主要目標是學習利用 localStorage 在本地儲存的方法,

課程影片:JS30 15
導讀影片:Alex

初始文件

Github 檔案位置:15 - LocalStorage

網頁一開始的樣子如下,這個清單目前還沒有任何功能

可以先去看看 最後的成品

正式製作

流程

將程式的要求拆分步驟後,我們需要做的事情如下

  1. 輸出輸入的文字至畫面,並在本地端儲存
  2. 以利用 HTML 元素數值的方式勾選 checkbox,並將結果儲存

輸出輸入的文字至畫面,並在本地端儲存

初始的程式碼如下,主要就是整合了這半個月學到的種種知識,即可完成在畫面上動態新增清單

const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
const items = []; 

function addItem(e) {
  e.preventDefault(); // 取消 DOM 的預設操作
  const text = (this.querySelector('[name=item]')).value; // 抓取輸入框的值
  const item = {
    text,
    done: false
  };

  items.push(item); 
  populateList(items, itemsList); // 將輸入的 item 輸出至網頁上
  this.reset(); // 重置輸入框
}

function populateList(plates = [], platesList) {
  platesList.innerHTML = plates.map((plate, i) => {
    return `
      <li>
        <input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''} />
        <label for="item${i}">${plate.text}</label>
      </li>
    `;
  }).join(''); // 消除 List 元素之間自動有的逗號
}

addItems.addEventListener('submit', addItem);

但目前的網頁只要刷新了資料就會不見,這裡我們會用到 Storage.setItem() ,這個函式可以將資料以 JSON 的格式(以JSON.stringify() 轉換)儲存在 F12 -> Application -> Local Storage 中,即使關閉網頁依舊存在

如此我們只要讀存在 Local Storage 中的資料就可以做到資料的儲存

const items = JSON.parse(localStorage.getItem('items')) || []; // 如果有本地端儲存的 items 變數則使用,否則為空

function addItem(e) {
//...
    localStorage.setItem('items', JSON.stringify(items)); // 在本地端設置名為 'items' 的變數,並存入 JSON 後的 items
}

populateList(items, itemsList); // 如果有本地端儲存的 items 則先輸出到畫面

到此就完成了大部份的功能,在關閉網頁後已經可以儲存資料了

以利用 HTML 元素數值的方式勾選 checkbox,並將結果儲存

上次做 checkbox 的偵測時我們需要用 forEach 去幫所有 checkbox 做監聽

但我們其實可以在 HTML 就設定好,然後善用 target 中的 dataset.index 去代替這件事情

具體的執行邏輯就是在整份 itemsListclick 事件監聽,當觸發 click 事件後,可以發現 console.log(e.target.dataset.index) 吐出被點擊的那個 DOM 的 index,我們就可以利用這數值去做 item 的 done 轉換,並在轉換後丟進 localStorage

function toggleDone(e) {
  console.log(e.target.dataset.index);
  if (!e.target.matches('input')) return; // skip this unless it's an input
  const el = e.target;
  const index = el.dataset.index;
  items[index].done = !items[index].done;
  localStorage.setItem('items', JSON.stringify(items));
  populateList(items, itemsList);
}

itemsList.addEventListener('click', toggleDone);

最後程式碼

const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
const items = JSON.parse(localStorage.getItem('items')) || []; // 如果有本地端儲存的 items 變數則使用,否則為空

function addItem(e) {
  e.preventDefault(); // 取消 DOM 的預設操作
  const text = (this.querySelector('[name=item]')).value; // 抓取輸入框的值
  const item = {
    text,
    done: false
  };

  items.push(item); 
  populateList(items, itemsList); // 將輸入的 item 輸出至網頁上
  localStorage.setItem('items', JSON.stringify(items)); // 在本地端設置名為 'items' 的變數,並存入 JSON 後的 items
  this.reset(); // 重置輸入框
}

function populateList(plates = [], platesList) {
  platesList.innerHTML = plates.map((plate, i) => {
    return `
      <li>
        <input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''} />
        <label for="item${i}">${plate.text}</label>
      </li>
    `;
  }).join(''); // 消除 List 元素之間自動有的逗號
}

function toggleDone(e) {
  console.log(e.target.dataset.index);
  if (!e.target.matches('input')) return; // skip this unless it's an input
  const el = e.target;
  const index = el.dataset.index;
  items[index].done = !items[index].done;
  localStorage.setItem('items', JSON.stringify(items));
  populateList(items, itemsList);
}

addItems.addEventListener('submit', addItem);
itemsList.addEventListener('click', toggleDone);

populateList(items, itemsList); // 如果有本地端儲存的 items 則輸出到畫面

完成結果圖

最後的成品

結語

以上是第十五天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<

How LocalStorage and Event Delegation work. #JavaScript30 15/30
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽 | Day 15:LocalStorage
MDN Web Docs


上一篇
JS30 -> 14 - JavaScript References VS Copying
下一篇
JS30 -> 16 - Mouse Move Shadow
系列文
剛接觸前端一個月的小白 - JavaScript30 挑戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言