---
# System prepended metadata

title: 'JavaScript 1. To Do List project  Practice '
tags: [JavaScript developer]

---

### 透過 YouTube 資源，學習別人如何製作 ToDoList

- [教學連結](https://www.youtube.com/watch?v=G0jO8kUrg-I)

### 透過 linear-gradient，實現背景漸變效果:

```
// HTML :

<div class="container"></div>
```

- 針對 container 設定 CSS。
  - 我學到了什麼: min-height: 100vh; -> 表示設定最低高度為當前瀏覽器的 100% 

  - 我學到了什麼: [linear-gradient](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient) -> 為背景顏色屬性，可透過兩種顏色設定行為及控制角度來達到背景顏色的操作設計。

```
// CSS:

.container {
  width: 100%;
  min-height: 100vh;
  background: linear-gradient(135deg, #153677, #4e085f);
  padding: 10px;
}
```

### 背景概況如下:

- 有些情況，我們單純只想用顏色混搭當作背景的話
  我們是不需要透過插入圖片來完成顏色混搭，透過 linear-gradient 也可做到!

![](https://hackmd.io/_uploads/Skx4S4h2n.png)



### 繼續完成程式碼：

- 這邊我們在建立一個 .todo-app 
  裡面有一個 h2 title , 旁邊可以放置一個自己的圖片當作 logo。
  「請注意，請放置沒有版權使用問題的圖片。」

![](https://hackmd.io/_uploads/rkz2wN2nn.png)



```
// HTML:

    <div class="container">
      <div class="todo-app">
        <h2>
          To-Do-List <img class="logo" src="./img/icon.avif" alt="logo" />
        </h2>
      </div>
    </div>
```

- todo-app 設定 styling

```
// CSS:

.todo-app {
  width: 100%;
  max-width: 540px;
  background-color: #fff;
  margin: 100px auto 20px;
  padding: 40px 30px 70px;
  border-radius: 10px;
}
```

- 設定 title & img 

```
// CSS:

.todo-app h2 {
  color: #002765;
  display: flex;
  align-items: center;
  margin-bottom: 20px;
}

img {
  border-radius: 50%;
}

.todo-app h2 img {
  width: 60px;
  margin-left: 10px;
}

```
![](https://hackmd.io/_uploads/BkWw6Nh23.png)

### 設定 輸入欄位 & 按鈕：

```
// HTML:

    <div class="container">
      <div class="todo-app">
        <h2>
          To-Do-List <img class="logo" src="./img/icon.avif" alt="logo" />
        </h2>
        <div class="row">
          <!-- 設置 row -->
          <input type="text" id="input-box" placeholder="Add your text" />
          <button>Add</button>
        </div>
      </div>
    </div>
```

![](https://hackmd.io/_uploads/rkjXRV3hh.png)

- .row 設定 styling

```
// CSS:

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #edeef0;
  border-radius: 30px;
  padding-left: 20px;
  margin-bottom: 25px;
}

```
![](https://hackmd.io/_uploads/BkJWyrnnh.png)

- 這邊我們可以注意到我們的 input 欄位跟 backgroud 看起來有點怪怪的，我們將針對 input 做一些 style 調整。

```
// CSS:

input {
  flex: 1;
  border: none;
  /* 取消外框 */
  outline: none;
  /* transparent - 可透過這個設定來使該元素的背景透明，至於父元素之上 */
  background: transparent;
  padding: 10px;
}

```

- 修改以後：
   - 我學到了什麼:  取消外框 - `outline: none;`
   - 我學到了什麼: ` background: transparent;` 當下背景透明
![](https://hackmd.io/_uploads/r1vGZSn32.png)


### 針對按鈕做樣式設計：

- 我學到了什麼: `cursor: pointer` -> 用戶游標指向在元素上，可產生一個手指的圖示

```
// CSS:

button {
  border: none;
  /* 取消外框 */
  outline: none;
  padding: 16px 50px;
  background: #ff5945;
  color: #fff;
  font-size: 16px;
  /* cursor: pointer , 用戶游標指向在元素上，可產生一個手指的圖示 */
  cursor: pointer;
  border-radius: 40px;
}
```

- 成果圖示:

![](https://hackmd.io/_uploads/Skkx9Bn3h.png)

### 於 .todo-app 下設置 id="list-container"

```
// CSS:

   <div class="container">
      <div class="todo-app">
        <h2>
          To-Do-List <img class="logo" src="./img/icon.avif" alt="logo" />
        </h2>
        <div class="row">
          <input type="text" id="input-box" placeholder="Add your text" />
          <button>Add</button>
        </div>
        <!-- list-container -->
        <ul id="list-container">
          <li>Task 1</li>
          <li>Task 2</li>
          <li>Task 3</li>
        </ul>
      </div>
    </div>
```

### 針對 ul 撰寫 style：

- 細節 # 透過 background-image 設定 uncheck image
       ::before 偽元素實現 style
       
```
// CSS:

ul li {
  list-style-type: none;
  font-size: 17px;
  padding: 12px 8px 12px 50px;
  /* 此設定可以阻止 user 選取內容 */
  user-select: none;
  cursor: pointer;
  position: relative;
}

/* li 前面(::before)添加偽元素 */

ul li::before {
  content: "";
  position: absolute;
  height: 28px;
  width: 28px;
  border-radius: 50%;
  background-image: url(/img/unchecked.png);
  background-size: cover;
  background-position: center;
  top: 8px;
  left: 8px;
}
```       
![](https://hackmd.io/_uploads/rkod-U2n2.png)

### ul.checked 樣式預先設置

```
// HTML: 

        <ul id="list-container">
          <li class="checked">Task 1</li>
          <li>Task 2</li>
          <li>Task 3</li>
        </ul>
```

- 設計 li 刪除線樣式

```
// CSS:

/* li 刪除線樣式 */
ul li.checked {
  color: #555;
  text-decoration: line-through;
}
```
![](https://hackmd.io/_uploads/H1hXzLn32.png)

- 設計 li.checked 完成的圖示：
  - 可以運用::before 技巧。
```
ul li.checked::before {
  background-image: url(/img/checked.png);
}
```

- 在此就可以看到：
  - 完成與未完成的完整區別樣貌。

![](https://hackmd.io/_uploads/Bkt7mL322.png)

### 前置樣式設定完成，後續將執行 JavaScript 撰寫：

1. 先回到 HTML 檔案，將剛剛設計的 ul > li 區塊給他註解起來。


```
// HTML:

        <ul id="list-container">
          <!-- <li class="checked">Task 1</li>
          <li>Task 2</li>
          <li>Task 3</li> -->
        </ul>
```


2. 開啟 js 檔案，撰寫 JavaScript:
   - 如要使 buuton 產生按鈕事件效果
     手動在標籤旁加入 'onclick' 並導入 addTask()
```
// JS:

// 指向 #input-box 欄位
const inputBox = document.getElementById("input-box"); 
 // 指向 ul 區塊
const listContainer = document.getElementById("list-container");


// 加入待辦 

btn.addEventListener("click", function () {
  if (inputBox.value === "") {
    alert("You must write something!");
  } else {
    let li = document.createElement("li"); // 宣告一個 li 變數,添加一個 li
    li.innerHTML = inputBox.value; // li 標籤裡的內容，根據我們所輸入的內容
    listContainer.appendChild(li); // DOM 操作,用於添加子元素的語法 , 對象是 li
  }
 // 優化設定，輸入內容後消除輸入欄位文字：
 inputBox.value = "";
});
```

- 學習點: `document.createElement("li")`
  此語法用於建構在網頁上產生一個 elements Tag
  
- 並且，我們所添加的 li 內容都來自於我們所輸入的待辦事項內容：
  - 也就是: `li.innerHTML = inputBox.value;  `
    透過，innerHTML 方式。
    
- 上述行為完成，指定 ul id，添加一個子元素行為:
  `listContainer.appendChild(li); `   
  
![](https://hackmd.io/_uploads/HJASkPh33.png)

### 我們需要在 list 內容旁添加一個 「刪除圖示」

- 在 else 後面添加 span

```
// JS:

btn.addEventListener("click", function () {
  if (inputBox.value === "") {
    alert("You must write something!");
  } else {
    let li = document.createElement("li");
    li.innerHTML = inputBox.value;
    listContainer.appendChild(li);
    // 除了 li 內容，我們也須針對內容旁邊增加一個 delete 圖示
    let span = document.createElement("span");
    span.innerHTML = "\u00d7";  
    li.appendChild(span);
  }
  inputBox.value = "";
});
```

![](https://hackmd.io/_uploads/Sy6SWvhhn.png)



- 留意一下這個地方：
  `span.innerHTML = "\u00d7";  `
  - 這段 code "\u00d7" -> 使用了 （HTML symbols）是一些特殊的字符

### 接著，我們針對這個字符來設計 CSS

```
// CSS:

ul li span {
  position: absolute;
  top: 5px;
  right: 0;
  width: 40px;
  font-size: 22px;
  color: #555;
  line-height: 40px;
  text-align: center;
  border-radius: 50%;
}

// 添加滑鼠移動樣式:

ul li span:hover {
  background: #edeef0;
}
```
![](https://hackmd.io/_uploads/SkmuXwh33.png)


### 刪除待辦事項

1.   點擊該區域，如果獲取標籤屬性為「LI」，則切換元素 
     - 這邊的 **checked** 就是我們在 CSS 預先寫好的刪除線樣式。
```
 e.target.classList.toggle("checked");
```

2.   點擊該區域(SPAN)，則會移除父層元素(LI) -> 此方法即可將待辦給刪除

```
 e.target.parentElement.remove();
```


```
listContainer.addEventListener("click", function (e) {
  if (e.target.nodeName == "LI") {
    e.target.classList.toggle("checked");
  } else if (e.target.nodeName === "SPAN") {
    e.target.parentElement.remove();
  }
});
```

![](https://hackmd.io/_uploads/B1dG6t33n.png)

###  localStorage 瀏覽器資料儲存

- 完成了待辦清單，不過這邊還有一些小小的問題
  關閉了瀏覽器以後，待辦就會被清除了，這邊需要透過一個方法
  讓資料可以存在於這個瀏覽器上。
  
  
- localStorage , setItem  
  - 增加本地儲存空間：
  - 資料儲存方式，為 'key','value'
    - 如下所示， key = 'data' -> 自定義 name
    - value = ->   listContainer.innerHTML
```
function saveData() {
localStorage.setItem("data", listContainer.innerHTML);
}
```  

### 從瀏覽器了解 setItem , key & value

- 右鍵 -> 開發者工具 -> Application -> 左側 localStorage
  可以看到我們暫存的資料庫，點下去並且就可以去看到右邊的
  key & value ~

![](https://hackmd.io/_uploads/SyiHU9n32.png)


- 設定完 localStorage setItem 還需要在 listContainer
  導入 saveData()，添加此函式的用意在於
  我們執行了任何動作，都會透過行為紀錄於 listContainer 
  這個區塊的資料變化也就是 setItem 對應的 value
  
  
```
listContainer.addEventListener("click", function (e) {
  if (e.target.nodeName == "LI") {
  ("checked")
    e.target.classList.toggle("checked");
    saveData();
  } else if (e.target.nodeName === "SPAN") {
    e.target.parentElement.remove();
    saveData();
  }
});

```

### localStorage getItem 撈取 key value

- 由下所示：
  這段 code 表示我的待辦區塊資料顯示，會源自於 
  `localStorage.getItem("data");`
  透過 listContainer.innerHTML 方式。
```

function showTask() {
  listContainer.innerHTML = localStorage.getItem("data");
}

showTask();
```

- 最後在 JS Code 最後一行寫上  `showTask();`
  該 ToDoList 專案就完成。

- 藉由此方式可實現瀏覽時緩存資料的行為
  我們最後做了什麼事，瀏覽器就清楚地幫我們記錄起來，
  
  
### 更多參考資料:


- [localStorage 筆記 - 鐵人賽痞客邦](https://ithelp.ithome.com.tw/articles/10308554?sc=iThelpR)

- [認識瀏覽器的神秘儲存空間 - localStorage](https://5xruby.tw/posts/localstorage)
