0%

JS 筆記 - 做一個 TodoList

練習 TodoList 的原因

TodoList 看似簡單的介面,但其實隱藏了很多小細節,記錄一下這次的練習,預計要完成的畫面如下:
todolist


練習重點

  • 切版的熟悉度。
  • 綁定 DOM 元素。
  • 紀錄資料再 localStorage。
  • 透過 setItemgetItem 實現新增待辦。
  • 透過 datasetsplice 屬性抓出排序與刪除資料。

製作 TodoList

navbar 用 Bootstrap 4 套件很快速就可以完成了,相關的 CSS 再看 codepen,就不做太多陳述。

下方的 content 分成兩欄,這邊稍微紀錄一下:

左邊 siderbar 設定為 Width:30%

右邊 inputbarwidth: 67%,再往左邊推 margin-left: 3%,總共為 70%

因為最下面的 taskList 清單想要再 inputbar 下方,且限制其寬度, CSS 設定為 width: 70%margin-left: 26%

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="content">
<div class="siderbar">
<ul>
<li><a href="#">今天</a></li>
<li><a href="#">明天</a></li>
<li><a href="#">未來七天</a></li>
</ul>

</div>
<div class="inputbar">
<input type="text" name="task" id="task" placeholder="請輸入待辦事項">
<button class="btn"><i class="fas fa-plus"></i></button>
</div>
<!-- input -->
</div>
<ul class="taskList">
</ul>

</div>

SCSS

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
.content {
margin-top: 3%;
display: flex;

.siderbar {
width: 30%;
line-height: 2;
margin-right: 0;

a {
text-decoration: none;
color: $primary-color;

&:hover {
font-weight: bold;
}
}
}

.inputbar {
display: flex;
margin-left: 3%;
width: 100%;
height: 42px;
//限制高度,就能讓 inputbar 的高度固定,不會受 flex 影響

input {
width: 100%;
margin-right: 0.3em;
}
}

.btn {
background-color: $primary-color;
padding: 5px;
color: #fff;
font-size: 16px;
width: 42px;

&:hover {
background-color: (darken($color: $primary-color, $amount: 20%));
color: #fff;
}
}
}

以上是靜態頁面會呈現的樣子,但 todolist 需要有互動,可增加與刪除事項的功能,所以要加入 JavaScript。

JavaScript

先綁定資料,

1
2
3
4
5
6
var btn = document.querySelector(".btn");
//綁定 .btn
var input = document.querySelector("#task");
//綁定 input 中的 id
var list = document.querySelector(".taskList");
//綁定新增 todos 的清單 .taskList

宣告 getData 變數作為從 localStorage 取出 value,typeof 會是 string,

1
var getData = localStorage.getItem("task");

先宣告一個 getDataAry = 空值,如果 getData 是 true,會去解析 getDataAry 字串資料成陣列,否則就會空陣列。

1
2
3
4
5
6
7
var getDataAry = "";
if (getData) {
getDataAry = JSON.parse(getData); //將字串轉成陣列
} else {
getDataAry = [];
}
var taskList = getDataAry; //陣列資料

更新清單,組完字串後,會放在 .taskListul 中,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
updateList(); //讓後面新增與刪除的功能也吃到 funciton
//更新清單
function updateList() {
var len = taskList.length; //計算 taskList 的長度
var str = ""; //組字串
for (var i = 0; i < len; i++) {
str += `
<li>
<a data-num=${i}>
<i class='fas fa-times-circle'></i>
</a>${taskList[i]}
</li>`;
//字串加總後會產生 li,並加入 a 連結,新增一個 data-num 作為陣列排序,加上陣列資料
}
list.innerHTML = str; //每次更新就存回 localStorage 印在網頁上成字串

var taskListStr = JSON.stringify(taskList); //解析陣列成字串
localStorage.setItem("task", taskListStr); //把輸入的資料存到 localStorage 的 key, value
}

建立新增資料刪除資料監聽事件,

1
2
3
4
btn.addEventListener("click", getInput, false);
//新增監聽按鈕,當有點擊事件時得到 input 的值
list.addEventListener("click", delTask, false);
//新增監聽清單,當點擊事件時刪除 list 的值

當使用者輸入資料,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getInput() {
console.log(input.value);
var text = input.value; //簡易判斷是否為空值

if (text === "") {
//如果 input 裡面是空值
alert("您未輸入事項"); //會跳 alert 視窗
return;
}
//把 input 加入陣列
taskList.push(text); //輸入的值丟回代辦事項的陣列
input.value = ""; //清空輸入框
updateList();
//重新更新清單
}

當使用者刪除資料,點擊到的 nodeNameA 或是 I 就中斷,造成點選AI 就結束動作,而點到後面文字,也就是 LI 則被刪除,所以要把刪除的動作放在 if 判斷內就能點 icon 圖示刪除 todo

1
2
3
4
5
6
7
8
9
10
function delTask(e) {
var current = e.target.nodeName; //當刪除事件指的是自己的 nodeName
if (current == "A" || current == "I") {
var currentNum = e.target.dataset.num; //選取到自定義的 data-num
taskList.splice(currentNum, 1); //就刪除該筆的一筆資料
} else {
return;
}
updateList(); //重新更新清單
}

結語

JS 的互動行為有點細,跟人腦思維不太一樣,要一個口令一個動作,也不用想得太難,要直觀一點,可能人腦的思維可以很快速的整合一件事情的內容,但 JS 是要透過很多的行為告訴電腦該怎麼完成這些很細的動作。很有趣的練習!!

附上 codepen,可以玩玩看: https://codepen.io/hnzxewqw/pen/eYmRgoJ