---
# System prepended metadata

title: "todolist_音時艾拉 應援筆記\n✧*。٩(ˊωˋ*)و✧*。"
tags: [六角學院_JavaScript 必修篇 - 前端修練全攻略]

---

---
tags: 六角學院_JavaScript 必修篇 - 前端修練全攻略
---
todolist_音時艾拉 應援筆記
✧*。٩(ˊωˋ*)و✧*。
===

<iframe height="300" style="width: 100%;" scrolling="no" title="8/25 TodoList" src="https://codepen.io/ototoki_error/embed/PojwEoo?default-tab=html%2Cresult&editable=true" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/ototoki_error/pen/PojwEoo">
  8/25 TodoList</a> by 音時エラー⚙️ (<a href="https://codepen.io/ototoki_error">@ototoki_error</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>


0.如何內嵌codepen
---
1. 點擊在 Fork 旁邊的 Embed
2. 點選 Inframe ， 把code 貼到 HackMD 裡


1.新增資料
---
### HTML
1. 在標籤 input 內加入 id
2. 在標籤 a 內加入 id


```htmlmixed=
<div class="card input">
  <input type="text" placeholder="請輸入待辦事項" id="inputText" />
  <a href="#" class="btn_add" id="addBTN">+</a>
</div>
```


### JS
1. 創建變數 `inputText addBTN` 存入 DOM
2. 創建陣列 `todoData` 存取代辦事項
3. 監聽 `addBTN` 點擊事件，如果有，執行 `addTodo()`
4. function `addTodo()`
    1. 創建物件 `todo` 存取 3 個屬性`txt id checked` 
        1. `txt: inputText.value` 將輸入欄的內容存進去
        2. `id: new Date().getTime()` 創建一個 `Date` 物件，並使用 `.getTime()` 取得毫秒數，用來創造獨一無二的 id
        3. `checked: ""` 等下會使用改變 class 的方式更換造型
5. 如果 `todo.txt` 不是空字串，就用 `.unshift()` 加到陣列最前面，並將輸入欄清空


```javascript= 
const inputText = document.getElementById("inputText");
const addBTN = document.getElementById("addBTN");
let todoData = [];

// 1. 新增
addBTN.addEventListener('click', addTodo);
function addTodo() {
  let todo = {
    txt: inputText.value,
    id: new Date().getTime(),
    checked: '',
  };
  if (todo.txt != '') {
    todoData.unshift(todo);
    inputText.value = '';
  }
  updateList();
}
```


2.渲染
---
### HTML
1. 在標籤 ul 內加入 id


```htmlmixed=
<ul class="list" id="todoList"></ul>
```


### JS
1. 創建變數 `todoList` 存入 DOM
2. function `render(arr)`
    1. 創建變數 `str` 
    2. `arr.forEach()` 將每個陣列裡的東西跑過一次
        1. 將要新增的內容賦予 `str` ，並利用 Template literals 更改成物件內容
    3. 使用 `todoList.innerHTML` 更改內容


```javascript= 
// 2. 渲染
const todoList = document.getElementById('todoList');
function render(arr) {
  let str = '';
  arr.forEach((i) => {
    str += `
    <li data-id="${i.id}">
            <label class="checkbox" for="">
              <input type="checkbox" ${i.checked}/>
              <span>${i.txt}</span>
            </label>
            <a href="#" class="delete asd"></a>
          </li>
    `;
  });
  todoList.innerHTML = str;
}
```


3.tab 切換 (CSS樣式)
---
### HTML
1. 在標籤 ul 內加入 id


```htmlmixed=
<ul class="tab" id="tab"></ul>
```


### JS
1. 創建變數 `tab` 存入 DOM
2. 創建變數 `toggleStatus` 儲存現在的狀態(全部(預設)、待完成、已完成)
3. 監聽 `tab` 點擊事件，如果有，執行 `changeTab()`
4. function `changeTab()`
    1. 將變數 `toggleStatus` 更改成現在點擊的狀態，`.dataset` 可以取得標籤內 `data-*` 的值(以物件方式傳回)， `.dataset.tab` 可以取得 li 標籤裡 data-tab 的值
    2. 宣告變數 `tabs` 存入 DOM 陣列
    3. `tabs.forEach` 將 li 標籤裡 'class' 內的 'active' 移除
    4. 將點擊的li 標籤裡 'class' 內的 加上 'active'


```javascript= 
//3. tab 切換 (CSS樣式)
const tab = document.getElementById('tab');
let toggleStatus = 'all';
tab.addEventListener('click', changeTab);
function changeTab(e) {
  toggleStatus = e.target.dataset.tab;

  let tabs = document.querySelectorAll('#tab li');
  tabs.forEach((i) => {
    i.classList.remove('active');
  });
  e.target.classList.add('active');
  updateList();
}
```


4.刪除 & 切換 checked 狀態功能
---
### JS
1. 監聽 `todoList` 點擊事件，如果有，執行`deleteAndChecked()`
2. function `deleteAndChecked()`
    1. 宣告變數 `id` ，使用 `.closest('li')` 取得最靠近點選元素的 parents，使用 `.dataset.id` 可以取得 li 標籤裡 data-id 的值
    2. 如果點擊的 'class' 內容為 'delete'
        1. 取消 a 標籤預設效果
        2. 使用  `.filter() ` 將其他的物件留下
    3. 否則(切換 checked 狀態功能)
        1.  如果這個物件的 checked 屬性等於 'checked'，就把 checked 屬性改成空字串
        2.  否則就把 checked 屬性改成 'checked'


```javascript= 
// 刪除 & 切換 checked 狀態功能
todoList.addEventListener('click', deleteAndChecked);
function deleteAndChecked(e) {
  let id = e.target.closest('li').dataset.id;
  console.log(e.target.classList.value)
  if (e.target.classList.value == 'delete') {
    e.preventDefault();
    todoData = todoData.filter((i) => i.id != id);
  } else {
    // 切換 checked 狀態功能
    todoData.forEach((i, index) => {
      if (i.id == id) {
        if (todoData[index].checked == 'checked') {
          todoData[index].checked = '';
        } else {
          todoData[index].checked = 'checked';
        }
      }
    });
  }
  updateList();
}
```


5.更新代辦清單
---
### JS
1. function `updateList()`
    1. 宣告空陣列 `showData`
    2. 如果現在 `toggleStatus == 'all'`，保持原本 `todoData`
    3. 否則如果 `toggleStatus == 'work'` ，將 `todoData` 篩選出還沒完成的(該物件的 checked 屬性是空字串)
    4. 否則，將 `todoData` 篩選出還完成的(該物件的 checked 屬性是 'checked')
    5. 宣告變數 `workNum` 存入 DOM
    6. 宣告變數 `todoLength` 賦予從 `todoData` 篩選出還沒完成的(該物件的 checked 屬性是空字串)
    7. 利用 `workNum.textContent` 將內容改成待完成的數量(`todoLength.length`)
    8. 用 `render(showData)` 渲染出符合現在 toggleStatus 的物件
6. 呼叫 `updateList()` 初始化頁面



```javascript= 
// 5. 更新代辦清單
function updateList() {
  let showData = [];
  if (toggleStatus == 'all') {
    showData = todoData;
  } else if (toggleStatus == 'work') {
    showData = todoData.filter((i) => i.checked == '');
  } else {
    showData = todoData.filter((i) => i.checked == 'checked');
  }

  const workNum = document.getElementById('workNum');
  let todoLength = todoData.filter((i) => i.checked == '');
  workNum.textContent = todoLength.length;

  render(showData);
}

//初始
updateList();

```


6.刪除已完成 todo
---
### HTML
1. 在標籤 a 內加入 id


```htmlmixed=
<a href="#" id="deleteBTN">清除已完成項目</a>
```


### JS
1. 創建變數 `deleteBTN` 存入 DOM
2. 監聽 `deleteBTN` 點擊事件，如果有，執行 `function(e)`
4. `function(e)`
    1. 移除 a 標籤預設效果
    2. 篩選出還沒完成的(該物件的 checked 屬性不是 'checked')
    3. 使用 `updateList()` 更新


```javascript= 
// 6.刪除已完成 todo
const deleteBTN = document.getElementById('deleteBTN');
deleteBTN.addEventListener('click', function (e) {
  e.preventDefault();
  todoData = todoData.filter((i) => i.checked != 'checked');
  updateList();
});
```

7.優化
---
### JS
1. 監聽 `inputText` 按下鍵盤事件，如果有，執行 `function(e)`
4. `function(e)`
    1. 如果鍵盤按下的( e.key ) 是 'Enter' ，就執行 `addTodo()`



```javascript= 
// 7. 優化
inputText.addEventListener('keypress', function (e) {
  if (e.key == 'Enter') {
    addTodo();
  }
});
```