昨天成功把 LocalStorage 接進哈納小小記事本。
現在就算按:
F5
記事也不會集體失憶了。
本來覺得:
很好,這東西終於有一點記事本的樣子了。
結果用一用馬上發現新的問題。
我手滑輸入:
記得買哈納的罐罐罐罐罐罐
……
沒事。
刪掉就好。
然後我看了一下畫面。
蛤?沒有刪除鍵???
所以目前這個記事本的規則是:
寫出去的話,就像潑出去的水。
不是欸。
我只是寫記事本,不是在立誓欸 ==
所以 Day 29 決定把最後一個重要功能補起來:
刪除記事!
昨天的 renderNotes() 是:
function renderNotes() {
noteList.innerHTML = "";
notes.forEach(function (note) {
const li = document.createElement("li");
li.textContent = note.text;
noteList.appendChild(li);
});
}
今天要多一顆按鈕。
改成:
function renderNotes() {
noteList.innerHTML = "";
notes.forEach(function (note) {
const li = document.createElement("li");
const text = document.createElement("span");
const deleteBtn = document.createElement("button");
text.textContent = note.text;
deleteBtn.textContent = "刪除";
deleteBtn.dataset.id = note.id;
li.appendChild(text);
li.appendChild(deleteBtn);
noteList.appendChild(li);
});
}
現在每一筆記事旁邊都會多一顆:
刪除
終於。
寫錯字不用跟它相處一輩子了 XD
這裡多了一個:
deleteBtn.dataset.id = note.id;
因為每一篇記事原本都有自己的:
id
例如:
{
id: 1750000000000,
text: "記得買哈納的罐罐"
}
所以我把這個 id 放到按鈕身上。
產生出來的 HTML 概念上會像:
<button data-id="1750000000000">
刪除
</button>
之後按下刪除,
就可以知道:
你到底想刪哪一篇。
不然如果畫面上有十篇記事,
每一顆都叫「刪除」,
JavaScript 大概也會問:
好啊,所以你到底要刪誰???
看到這麼多刪除按鈕,
原本第一個想法可能是:
每顆按鈕都加 addEventListener()
但等等。
這個畫面好熟悉。
Day 20 才學過:
Event Delegation(事件代理)
所以這次直接監聽外面的:
noteList
noteList.addEventListener("click", function (event) {
if (event.target.tagName !== "BUTTON") {
return;
}
console.log(event.target.dataset.id);
});
這樣不管點的是哪一篇的刪除按鈕,
都可以透過:
event.target
知道真正被點到的是誰。
以前學的東西終於真的出現在作品裡。
Day 20 的我沒有白學 QQ
接下來就要從 notes 裡把那筆資料移除。
這時候又輪到之前學過的:
filter()
上班。
notes = notes.filter(function (note) {
return note.id !== id;
});
意思就是:
把不是這個 id 的記事全部留下。
那個被點到的記事?
不好意思。
你被篩掉了 XD
完整一點:
noteList.addEventListener("click", function (event) {
if (event.target.tagName !== "BUTTON") {
return;
}
const id = Number(event.target.dataset.id);
notes = notes.filter(function (note) {
return note.id !== id;
});
saveNotes();
renderNotes();
});
流程變成:
點刪除
↓
取得這篇記事的 ID
↓
用 filter() 移除資料
↓
重新存進 LocalStorage
↓
重新 render
如果只有:
notes = notes.filter(...)
再:
renderNotes();
畫面上的確會消失。
看起來超成功。
然後按一下 F5。
……
它又回來了。
哈囉???
你是幽靈記事是不是 ==
原因就是:
畫面跟 Array 雖然刪掉了,
但 LocalStorage 裡的舊資料還在。
所以刪除之後一定還要:
saveNotes();
把最新的 Array 再存一次。
這樣才是真的刪掉。
不是單純:
眼不見為淨。
既然現在一篇記事裡有:
記事內容 + 刪除按鈕
CSS 也稍微補一下:
#noteList li {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
margin-bottom: 10px;
padding: 12px 15px;
background-color: #fff0f3;
border-radius: 8px;
}
#noteList li span {
flex: 1;
word-break: break-word;
}
#noteList li button {
border: none;
padding: 8px 12px;
border-radius: 6px;
background-color: #ff6b81;
color: white;
cursor: pointer;
}
#noteList li button:hover {
opacity: 0.8;
}
前面學過的 Flexbox:
display: flex;
又來了。
突然覺得這 29 天學的東西,
真的很像一群同事。
平常各上各的班,
做作品的時候突然:
全部進會議室集合。
現在記事本的功能已經變成:
輸入記事
↓
按新增
↓
加入 Array
↓
存入 LocalStorage
↓
顯示到網頁
以及:
按刪除
↓
取得 ID
↓
filter() 移除資料
↓
更新 LocalStorage
↓
重新顯示
原本單獨學的:
filter()
event.target
LocalStorage
現在居然全部接在一起了。
這種感覺滿奇妙的。
以前是:
這個語法到底拿來幹嘛?
現在是:
喔,原來你在這裡等我。
到 Day 29,
哈納小小記事本現在已經可以:
從一開始只有:
<input>
<button>
慢慢加到現在,
終於開始真的像一個可以使用的小作品。
而且今天最有感的反而不是多了一顆「刪除」按鈕。
而是發現前面學過的:
Array、filter()、DOM、Event Delegation、LocalStorage、Flexbox……
真的開始自己串起來了。
哈納也從一開始只是:
console.log("哈納");
一路進化成現在直接擁有自己的記事本。
牠本人應該完全沒有同意這件事 XD

刪除後:

剩最後一天。
這次真的差不多要來看看,
這 30 天到底被我折騰出了什麼東西。
Day 29,完成!