目標
模擬餐廳菜單,在頁面中增加菜名,并且用 localStorage,使頁面重新整理之後仍保留原來菜名
播放
step 1 : 獲取 HTML 元素,並用變數儲存菜單資料
// 拿到 form 元素
const addItems = document.querySelector('.add-items')
// 拿到顯示菜單的列表 ul 元素
const itemsList = document.querySelector('.plates')
// 變數 items 為所有菜單内容,預設空陣列
const items = []
step 2 : 監聽 form 的 submit 事件
function addItem(e) {
// preventDefault() 避免 submit 預設行爲發生
e.preventDefault();
// 拿到 form 中 input 欄位的值
const text = this.querySelector('[name=item]').value;
// 宣告變數 item 為新增的菜單資料,包含 input 輸入的值以及勾選狀態(done)
const item = {
text,
done: false
}
console.log(item);
// 清空 input 欄位
this.reset();
}
// 監聽 form 的 submit 按鈕,並觸發 addItem function
addItems.addEventListener('submit', addItem);
step 3 : 建立 populateList function,將資料顯示在 HTML 中
function populateList(plates = [], platesList){
// map() 方法將每筆資料帶入 li 元素中,加上 join() 連接字串
platesList.innerHTML = plates.map((plate,index)=>{
return `
<li>
<input type="checkbox" data-index=${index} id="item${index}" ${plate.done? 'checked': ''}/>
<label for=item${index}>${plate.text}</label>
</li>
`
}).join('')
}
// 新增菜單
function addItem(e) {
e.preventDefault(); // 避免 submit 的預設行爲且表單送出之後的重新整理
const text = this.querySelector('[name=item]').value;
const item = {
text,
done: false
}
console.log(item);
// 將資料 push 到變數 items 陣列中儲存
items.push(item)
// 執行 populateList function, 並帶入參數 items, itemsList
// 讓資料顯示在畫面中
populateList(items, itemsList)
this.reset()
}
// 監聽 form 的 submit 按鈕,並觸發 addItem function
addItems.addEventListener('submit', addItem);
step 4 : 設定 localStorage
localStorage.setItem('name', 'value')
:儲存(用 JSON.stringify 將物件轉為 string)
localStorage.getItem('name', 'value')
:取值 (用JSON.parse()將 string 轉回來)
function addItem(e) {
...
populateList(items, itemsList);
// 將 items 的資訊儲存於browser 的 localStorage 中,
// 一個自訂 key 為"items",value 為變數 items 的物件
// localStorage 的值存的是字串,記得用 JSON.stringify 先轉爲字串
localStorage.setItem('items', JSON.stringify(items));
this.reset()
...
}
回到一開始宣告的變數 items,先判斷 browser 的localStorage 是否有 items 物件的值,若 localStorage 沒有此值,則設爲空陣列
// 記得將拿到的值從字串格式轉換為 JSON
const items = JSON.parse(localStorage.getItem('items')) || []
step 5 : 處理 checkbook 狀態
function toggleDone(e) {
// 這裡的 e.target 可能返回 input 及 label 兩個元素
// 偵測到的是 input 才執行 (<input type="checkbox".../>)
if (!e.target.matches('input')) return;
// 拿到 checkbox 中的 data-index 值
const el = e.target;
const index = el.dataset.index;
// 透過 items 和 index 可以得到 li 的資料
// 用 '!' 做一個 switch (若 done 為 true => 改為 false,反之亦然)
items[index].done = !items[index].done;
// 同步更新 localStorage 中的狀態
localStorage.setItem('items', JSON.stringify(items));
// 同步更新頁面的狀態
populateList(items, itemsList);
}
// 利用事件代理機制(Event Delegate),將監聽器掛在 父元素 ul 上,
// 監聽子元素 li 的click 事件,觸發時執行 toggleDone function
itemsList.addEventListener('click', toggleDone);
補充: 客制化 checkbox
/* checkbox 先不顯示 */
input[type='checkbox'] {
display: none;
}
/* 沒有 checked 時用僞元素的方式添加假的 checkbox */
input[type='checkbox'] + label:before {
content: '⬜️';
margin-right: 10px;
}
/* checked 時用僞元素的方式添加假的 checkbox */
input[type='checkbox']:checked + label:before {
content: '🌮';
}
參考資料:
- How LocalStorage and Event Delegation work. #JavaScript30 15/30 @Wes Bos
- [Alex 宅幹嘛] 👨💻 深入淺出 Javascript30 快速導覽 | Day 15:LocalStorage @Alex 宅幹嘛
- 15 - LocalStorage @guahsu
- 15 LocalStorage@soyaine
- [JS30] Day15: LocalStorage and Event Delegation@PJCHENder
- JS30-Day15-LocalStorage@王郁翔
- JS30 自學筆記 Day15_LocalStorage and Event Delegation@jen147774ny
- 详说 Cookie, LocalStorage 与 SessionStorage@邹润阳