大家好,時間過得真快,Todo List也進入第三天了!今天主要新增一個「依日期與時間排序」的功能,另外也把 HTML 版面跟 CSS 樣式整個順過一遍。
let sortByDate = false;
先加一個布林值狀態,預設是 false(不排序,維持原本的順序)。
const sortCheckbox = getElement<HTMLInputElement>("#sort-by-date");
沿用昨天的getElement<T>函式,把HTML裡新加的排序勾選框抓出來。
sortCheckbox.addEventListener("change", () => {
sortByDate = sortCheckbox.checked;
renderTodos();
});
監聽checkbox的change事件:使用者一勾選或取消勾選,就把sortByDate更新成checkbox 目前的勾選狀態,然後重新渲染畫面。這裡沒有另外寫一個「排序按鈕」,而是直接用 checkbox的狀態當開關。
function sortTodos(todoItems: Todo[]): Todo[] {
if (!sortByDate) {
return todoItems;
}
return [...todoItems].sort((first, second) => {
const dateOrder = first.date.localeCompare(second.date);
return dateOrder === 0 ? first.time.localeCompare(second.time) :
dateOrder;
});
}
sortTodos函式會接收一個Todo[]陣列,回傳排序後的結果。
sortByDate是 false:直接把傳進來的陣列丟回去,不做任何處理。sortByDate是true:因為<input type="date">抓出來的值格式固定是YYYY-MM-DD,<input type="time">抓出來的值格式固定是HH:mm,這兩種格式都是由較大的時間單位排到較小的時間單位,因此可以使用localeCompare()比較字串,不一定要轉成 Date 物件。date,如果日期相同(dateOrder === 0)才進一步比較time。[...todoItems] 先複製一份陣列再使用 sort(),因為 sort() 會直接修改原本的陣列。先建立新的陣列再排序,可以避免改動傳進來的 todoItems。sortTodosfunction renderTodos(): void {
const visibleTodos = sortTodos(filterTodos());
}
先用filterTodos()篩出目前分類要顯示的項目,再把結果丟進sortTodos()決定要不要排序。
<form id="todo-form" class="todo-form">
<div class="form-grid">
<div class="form-field">
<label for="todo-input">任務</label>
<input id="todo-input" type="text" placeholder="輸入任務名稱" />
</div>
<div class="form-field">
<label for="category-select">分類</label>
<select id="category-select" aria-label="選擇任務分類"></select>
</div>
<div class="form-field">
<label for="date-input">日期</label>
<input id="date-input" type="date" />
</div>
<div class="form-field">
<label for="time-input">時間</label>
<input id="time-input" type="time" />
</div>
<button type="submit">新增 Todo</button>
</div>
<p id="form-message" class="form-message" role="status"></p>
</form>
每個輸入欄位都包了一層.form-field,裡面加上對應的<label>(label的for屬性有對應到input的id)。
再來是新加的排序checkbox:
<label class="sort-control" for="sort-by-date">
<input id="sort-by-date" type="checkbox" />
依日期與時間排序
</label>
這裡直接把<input>包在 <label> 裡面,這樣使用者點擊文字「依日期與時間排序」也可以觸發勾選,不用非得點在那個小方框上。
今天的CSS主要是配合HTML的結構調整跟著改,這裡就直接展示一下重點的樣式,不特別逐行說明:
.form-grid {
display: grid;
grid-template-columns: 1fr;
gap: 14px;
}
.form-field {
display: grid;
gap: 6px;
}
.sort-control {
display: flex;
align-items: center;
gap: 8px;
margin: 14px 0;
color: #65718a;
cursor: pointer;
}
.sort-control input {
flex: none;
width: 18px;
height: 18px;
min-height: auto;
}
.form-grid跟.form-field:搭配今天新的表單結構,讓每個欄位跟它的label用Grid排整齊。.sort-control:排序checkbox搭配文字的簡單樣式,順便把cursor: pointer加上去,滑鼠移過去會變成手指,提示使用者這個區塊可以點擊。.todo-item 也微調成Grid版面:
.todo-item {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
column-gap: 10px;
row-gap: 6px;
padding: 12px;
border: 1px solid #e1e5ed;
border-radius: 8px;
}
.todo-details {
grid-column: 2;
color: #65718a;
font-size: 0.85rem;
}
.delete-button {
grid-column: 3;
grid-row: 1 / span 3;
color: #b42318;
border-color: #f0c6c2;
}
grid-template-columns: auto 1fr auto:將每個待辦事項分成勾選框 / 內容 / 刪除按鈕三欄grid-row: 1 / span 3:讓刪除按鈕從第1個grid row開始,跨越3個row,讓它能維持在右側。搭配align-items: center,讓刪除按鈕維持在右側並盡量保持垂直置中。今天將todo list的實作做了最後的修改,鐵人賽也漸漸來到了結尾,明天會寫點鐵人賽的心得,至於todo list是否會推送到github上,我會稍加考慮,今天就到這邊啦,大家再見!