JS30 day15 Local Storage and Event delegation

Posted by Anthony Chao on 2019-11-15

JS30 day15 - JS30 day15 Local Storage and Event delegation

作業內容

今天的內容在講說如何使用 Local Storage 還有如果要指定監聽的對象是動態變化的應該怎麼處理,網頁的部分是透過一個菜單來實作

學到什麼

  • JS

    1. preventDefault()
      參考資料:https://ithelp.ithome.com.tw/articles/10198999
    2. 使用屬性來當作選擇器 this.querySelector('[name=item]')
    1
    <input type="text" name="item" placeholder="Item Name" required="">
    1. 使用 this.reset(); 重置表單
    2. 在標籤裡面動態插入 <li>標籤:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function populateList(plates = [], plateList){
    plateList.innerHTML = plates.map((plate, i) => {
    return `
    <li>
    <label for="">${plate.text}</label>
    </li>
    `
    }).join("");
    }
    1. 在 html 裡面,如果有一個 checkbox 的 input
      以下三種狀況都還是會讓他呈現 checked:true 的狀態
    1
    2
    3
    <input type="checkbox" checked>
    <input type="checkbox" checked="qq">
    <input type="checkbox" checked=false>

    所以如果要根據屬性不同做出不同的 checked 狀態,只能加入 checked 或是空白字元

    1
    2
    //寫在 js 裡面
    <input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''}>
    1. localStorage 是個可以把資料儲存在瀏覽器的空間,不過要記得只能存字串
    1
    2
    3
    localStorage.setItem("items", items) //第一個參數是 key 的名字,第二個參數是要存的東西
    localStorage.getItem()
    localStorage.removeItem()

    而一開始的 items 就可以改為先試著從 localStorage 抓資料,沒有的話才給空陣列

    1
    const items = JSON.parse(localStorage.getItem('items')) || [];
    1. 我們要去捕捉每一個新長出來的 list 去監聽事件,對這種動態元素,最好的方式是去用他的父元素監聽,利用冒泡機制,所以父元素也會監聽到
    1
    2
    3
    4
    function toggleDone(e){
    console.log(e.target)
    }
    itemsList.addEventListener('click', toggleDone)

    但這樣會產生另一個問題,從 console log 可以看到每次都會出現兩個事件,所以必須再去濾除條件

    1
    2
    3
    function toggleDone(e){
    if(!e.target.matches('input')) return;
    }

參考資料:
https://github.com/wesbos/JavaScript30

code 內容:

HTML:

1
2
3
4
5
6
7
8
9
10
11
<div class="wrapper">
<h2>LOCAL TAPAS</h2>
<p></p>
<ul class="plates">
<li>Loading Tapas...</li>
</ul>
<form class="add-items">
<input type="text" name="item" placeholder="Item Name" required>
<input type="submit" value="+ Add Item">
</form>
</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
html {
box-sizing: border-box;
background: url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat;
background-size: cover;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-family: Futura,"Trebuchet MS",Arial,sans-serif;
}

*, *:before, *:after {
box-sizing: inherit;
}

svg {
fill:white;
background: rgba(0,0,0,0.1);
padding: 20px;
border-radius: 50%;
width: 200px;
margin-bottom: 50px;
}

.wrapper {
padding: 20px;
max-width: 350px;
background: rgba(255,255,255,0.95);
box-shadow: 0 0 0 10px rgba(0,0,0,0.1);
}

h2 {
text-align: center;
margin: 0;
font-weight: 200;
}

.plates {
margin: 0;
padding: 0;
text-align: left;
list-style: none;
}

.plates li {
border-bottom: 1px solid rgba(0,0,0,0.2);
padding: 10px 0;
font-weight: 100;
display: flex;
}

.plates label {
flex: 1;
cursor: pointer;
}

.plates input {
display: none;
}

.plates input + label:before {
content: '⬜️';
margin-right: 10px;
}

.plates input:checked + label:before {
content: '🌮';
}

.add-items {
margin-top: 20px;
}

.add-items input {
padding: 10px;
outline: 0;
border: 1px solid rgba(0,0,0,0.1);
}

JS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
const items = JSON.parse(localStorage.getItem('items')) || [];

function addItem(e){
e.preventDefault();
const text = (this.querySelector('[name=item]')).value;
const item = {
text: text,
done: false
}
items.push(item);
populateList(items, itemsList)
localStorage.setItem("items", JSON.stringify(items))
this.reset();
}

function populateList(plates = [], plateList){
plateList.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("");
}

function toggleDone(e){
if(!e.target.matches('input')) return;
const el = e.target;
const index = el.dataset.index;
items[index].done = !items[index].done
localStorage.setItem("items", JSON.stringify(items))
}

addItems.addEventListener('submit', addItem)
itemsList.addEventListener('click', toggleDone)
populateList(items, itemsList) // 上面那一列是表單送出才會發生作用,這一列是重新整理或者重新進到這個網頁都會發生作用




prevent_hack