# 認識瀏覽器的儲存空間-localStorage

### :gem:何謂localStorage
localStorage是由html5所提供的一個web storage,有下列幾項特點:
* 無法[跨域](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/CORS)使用,與cookie一樣只認domain name
* 達到5MB的儲存數據空間可以使用來降低request數量
* 用來儲存一些不重要但卻影響著效能等等的資訊。
---
### :gem:關於localStorage、sessionStorage、cookie 差異
| 項目 | localStorage | sessionStorage | Cookie |
| ---------------- | -------------------------------------------- | -------------------- | ------------------------------------ |
| 儲存數據 | 可以達到 5M 或更大 | 可以達到 5M 或更大 | 不能超過4k |
| 生命週期 | 瀏覽器關閉後資料不會移除,除非用戶端清除資料 | 刷新頁面資料依舊存在,關閉瀏覽器後資料移除 | 在後端設置的cookie過期時間內都會有效 |
| 傳遞資料到Server | 否 | 否 | 是 |
---
### :pencil:localStorage 簡單練習
#### <font color=#FF6600>**PART1**</font>
最近在工作實作上遇到下面的情境:speech_balloon:
(待補)
想到的兩種解法是
1.判斷是否打過API
2.使用localStorage儲存數據
最後我選擇用localStorage實作
透過這兩種方式來記住使用者是否曾經點擊過此按鈕,
若已點擊過A按鈕,就算重整頁面B按鈕也會是取消禁用的狀態
#### :bulb:知識點
**localStorage**
1. `localStorage.setItem('key','value')`:透過setItem指定物件屬性的`key`跟`value`
2. `locaStorage.getItem('key')`:透過getItem方法屬性中`key`,可以得到屬性中對應的`value`
**Event**
1. [target.addEventListener](https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener)
> html
```
<div>
<ul>
<li style="margin-left:45px; list-style-type:none">
<button type="button"
class="download">A</button>
</li>
<li style="margin-left:45px; list-style-type:none">
<button type="button"
class="download" disabled="disable">B</button>
</li>
</ul>
</div>
```
> javascript
```
let csrBtn = document.querySelector(".download");
function saveBtnClick() {
localStorage.setItem("setValue", 1); //儲存到localStorage 記錄使用者是否點擊過
}
csrBtn.addEventListener("click", saveBtnClick);
let str = localStorage.getItem("setValue"); //透過屬性的中的key,得到對應的value
if (str == 1) {
$("#touchBtn").removeAttr("disabled");
}
```
#### <font color=#FF6600>**PART2**</font>
[JavaScript30-NO.15 ](https://github.com/soyaine/JavaScript30)
透過localStorage的作法做資料的新增刪除。
#### :bulb:知識點
**Event**
1. event.preventDefault
2. [event.addEventListener](https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener)
**localStorage**
1. `localStorage.setItem('key','value')`
2. `locaStorage.getItem('key')`
**JSON**
1. `JSON.stringify()`
2. `JSON.parse()`
**作法:**
:one:取得form元素,並宣告一個空陣列準備放入資料。
> javascript
```
const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
var items = [];
```
:two:寫一個addItem函式,選取form中輸入框欄位值
```
function addItem(e) {
e.preventDefault(); //避免每新增一筆資料時就重整一次頁面
const text = this.querySelector('[name=item]').value;
const item = {
text: text, //要放入的清單
done: false //是否勾選
}
items.push(item);
this.reset();
.....
}
```
:three:顯示新增清單
```
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('');
}
```
* [ES6寫法在函式中給予參數的地方放入預設值](https://pjchender.blogspot.com/2017/01/es6-default-value.html)
* 使用map將所有陣列中的元素依序分別傳入一次至 callback 函式當中,並以此回呼函式每一次被呼叫的回傳值來建構一個新的陣列
* 使用`join`將陣列所有元素連結,合併成一個字串。
:four: 再回到addItem函式把[key,value]寫入localStorage
```
function addItem(e) {
.....
populateList(items, itemsList); //輸入送出後重新列出物件字串
localStorage.setItem('items', JSON.stringify(items));
.....
}
```
將items(自定義)存入localStorage中,因localStorage值是字串,需透過JSON.stringify將
物件或陣列轉為字串。
若沒轉為字串,新增資料時會得到下面的結果

:five:儲存checkbox狀態
```
function toggleDone(e) { //check
if (!e.target.matches('input')) return; //點擊的位置是否是input
const el = e.target;
const index = el.dataset.index; //取得checkbox位置
items[index].done = !items[index].done; //checkbox true or false
populateList(items, itemsList); //更新數據
localStorage.setItem('items', JSON.stringify(items)); //更新後的狀態寫入localStorage
}
addItems.addEventListener('submit', addItem);
itemsList.addEventListener('click', toggleDone);
populateList(items, itemsList);
```
:six: 新增刪除、選取所有checkbox、取消所有checkbox
```
const checkAllBtn = document.querySelector('.check-all');
const unCheckAllBtn = document.querySelector('.uncheck-all');
const deleteAllBtn = document.querySelector('.delete-all');
```
```
checkAllBtn.addEventListener('click', () => {
//透過迴圈遍歷每個item將checkbox狀態改為勾選
items.forEach(item => {
item.done = true;
});
populateList(items, itemsList); //更新數據
localStorage.setItem('items', JSON.stringify(items));
});
unCheckAllBtn.addEventListener('click', () => {
//遍歷迴圈的每個item將checkbox狀態改為取消勾選
items.forEach(item => {
item.done = false;
});
populateList(items, itemsList);//更新數據
localStorage.setItem('items', JSON.stringify(items));
});
deleteAllBtn.addEventListener('click', () => {
items = []; //將一開始宣告的陣列設為空值
populateList(items, itemsList);//更新數據
localStorage.setItem('items', JSON.stringify(items));
});
```
DEMO:[https://evalin0316.github.io/localStorage/localStorage.html](https://evalin0316.github.io/localStorage/localStorage.html)
> 參考資料:
>* http://techaride.blogspot.com/2012/07/javascript-localstorage.html
>* https://github.com/FEGuideTeam/FEGuide/tree/master/html%E9%97%AE%E9%A2%98