728x90
안녕하세요 오늘은 js로 투두리스트 만드는 법을 알아보겠습니다. 일전에도 투두리스트에 대해 만든 적이 있는데요 (이전 포스트 참고바랍니다.), 오늘은 이전과 달리 저장은 local Strorage를 사용할 것이고(localStroage포스트 참고) 완료가 될 때마다 게이지로 표시하여 달성률을 시각적으로 보여주도록 해보겠습니다.
완성 시 아래와 같이 동작합니다.
아래는 전체 코드입니다.
todo.html
<h1>미니 투두리스트</h1>
<form id="todo-form">
<input type="text" placeholder="Add a new task">
<button type="submit">추가</button>
<div id="progress-bar">
<div id="progress"></div>
</div>
</form>
<ul id="todo-list">
</ul>
<div id="congrats">
<h2>축하합니다!</h2>
<p>해야할 일을 모두 완료했습니다.</p>
</div>
todo.css
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 {
text-align: center;
margin-top: 50px;
}
form {
text-align: center;
margin-top: 30px;
}
input[type="text"] {
padding: 10px;
font-size: 16px;
border-radius: 5px;
border: none;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
}
input[type="checkbox"]:checked + span {
text-decoration: line-through;
}
button {
padding: 10px;
font-size: 16px;
border-radius: 5px;
border: none;
background-color: #4CAF50;
color: white;
cursor: pointer;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
}
button:hover {
background-color: #3e8e41;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: flex;
align-items: center;
margin-bottom: 10px;
font-size: 16px;
}
li input[type="checkbox"] {
margin-right: 10px;
}
#progress-bar {
width: 30%;
height: 20px;
margin: auto;
background-color: #f2f2f2;
margin-top: 30px;
bottom: 30px;
left: 0;
right: 0;
}
#progress {
height: 20px;
background-color: #4CAF50;
width: 0%;
transition: width 0.5s ease;
}
#congrats {
display: none;
text-align: center;
margin-top: 50px;
}
#congrats h2 {
font-size: 32px;
}
#congrats p {
font-size: 20px;
}
#todo-list {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
todo.js
// HTML에서 필요한 요소들을 가져오기
const form = document.getElementById("todo-form"); // Todo Form
const input = document.querySelector("input"); // Todo 입력 필드
const ul = document.getElementById("todo-list"); // Todo List
const progressBar = document.getElementById("progress"); // ProgressBar
const congrats = document.getElementById("congrats"); //전부 완료시 보여지는 축하 메시지
// Todo List를 저장할 배열
let todos = [];
// Local Storage에서 저장된 Todo List를 불러와서 todos 배열에 저장한다
const fetchTodos = () => {
todos = JSON.parse(localStorage.getItem("todos")) || [];//"todos"가 키값
}
// Todo List에 새로운 Todo를 추가한다
const addTodo = () => {
//0.입력 필드의 값이 비어있는 경우 함수를 종료.(추가할 필요가 없기 때문)
if (input.value.trim() === "") {
return;
}
//1-1.입력값이 있는경우 새로운 Todo 객체를 생성
const todo = {
title: input.value,
completed: false
};
//1-2.todos 배열에 새로운 Todo를 추가
todos.push(todo);
//1-3.Local Storage에 todos 배열을 저장
localStorage.setItem("todos", JSON.stringify(todos));
//1-4.입력 필드를 초기화한다
input.value = "";
//2.Todo List를 다시 렌더링한다
renderTodos();
}
// Todo List에서 Todo를 삭제
const removeTodo = (index) => {
// todos 배열에서 해당 인덱스의 Todo를 삭제
todos.splice(index,1);
// Local Storage에 todos 배열을 저장
localStorage.setItem("todos", JSON.stringify(todos));
// Todo List를 다시 렌더링
renderTodos();
}
// Todo List에서 Todo를 체크한다
const toggleCompleted = (index) => {
// 해당 인덱스의 Todo의 completed 속성을 반전시켜 값 얻기(true,false)
todos[index].completed = !todos[index].completed;
// Local Storage에 todos 배열을 저장한다
localStorage.setItem("todos", JSON.stringify(todos));
// ProgressBar를 업데이트한다
updateProgressBar();
// 모든 Todo가 완료되었는지 체크한다
checkCompleted();
}
// Todo List에서 하나의 Todo를 렌더링한다
const renderTodo = (todo, index) => {
// Todo 항목을 담을 li 요소를 생성한다
const li = document.createElement("li");
// Todo 항목의 체크박스를 생성한다
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = todo.completed;
checkbox.addEventListener("change", () => toggleCompleted(index));
// Todo 항목의 제목을 생성한다
const span = document.createElement("span");
span.innerText = todo.title;
// Todo 항목의 삭제 버튼을 생성한다
const deleteBtn = document.createElement("button");
deleteBtn.innerText = "X";
deleteBtn.addEventListener("click", () => removeTodo(index));
// li 요소에 체크박스, 제목, 삭제 버튼을 추가한다
li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(deleteBtn);
// Todo List(ul 요소)에 li 요소를 추가한다
ul.appendChild(li);
}
// Todo List 전체 렌더링하기
const renderTodos = () => {
ul.innerHTML = ""; // ul 엘리먼트의 innerHTML을 빈 문자열로 초기화
todos.forEach(renderTodo); // todos 배열에 저장된 각각의 Todo를 renderTodo 함수를 이용하여 li 엘리먼트로 변환하여 ul 엘리먼트에 추가
updateProgressBar(); // ProgressBar 업데이트
checkCompleted(); // 모든 Todo가 완료되었는지 체크하여, 축하 메시지를 보이거나 감춤
}
// ProgressBar 업데이트하기
const updateProgressBar = () => {
const completedCount = todos.filter(todo => todo.completed).length;
// todos 배열에서 completed 속성이 true인 todo 개수를 세어 completedCount 변수에 할당
const percent = (todos.length > 0) ? (completedCount / todos.length) * 100 : 0;
// todos 배열의 크기가 0보다 크면, todos 배열에서 completed 속성이 true인 todo 개수의 비율을 계산하여 100을 곱함. 아니면, 0을 할당
progressBar.style.width = percent + "%";
// ProgressBar의 width 속성을 변경하여 완료된 Todo의 비율을 나타내는 막대의 길이를 조절
}
// 모든 Todo가 완료되었는지 체크하기
const checkCompleted = () => {
if (todos.length === 0) { // todos 배열의 크기가 0이면, 축하 메시지를 감춤
congrats.style.display = "none";
} else if (todos.every(todo => todo.completed)){ // todos 배열의 모든 todo가 completed 속성이 true이면, 축하 메시지를 보임
congrats.style.display = "block";
} else { // 그 외의 경우, 축하 메시지를 감춤
congrats.style.display = "none";
}
}
// 초기화
fetchTodos(); // Local Storage에서 Todo List 불러오기
renderTodos(); // Todo List 렌더링하기
// 폼 제출 이벤트 리스너 등록
form.addEventListener("submit", event => {
event.preventDefault(); // 기본 동작(새로고침) 방지
addTodo(); // Todo List에 새로운 Todo 추가하기
}); // 폼 제출 이벤트 리스너 등록하기
-자세한 내용은 아래 링크 참고 부탁드립니다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/every
https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault
https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage
'JavaScript' 카테고리의 다른 글
[Javascript] 스크롤 이벤트를 활용한 동적 요소 표시 (0) | 2023.08.02 |
---|---|
[JavaScript] Owl Carousel을 활용한 캐러셀 구현하기 (0) | 2023.07.29 |
[JavaScript] 텍스트 더보기 및 줄이기 구현하기 (0) | 2023.07.14 |
[javaScript] contenteditable 속성으로 row 수정,저장하기. (0) | 2023.07.09 |
[JavaScript] C3.js를 활용하여 차트 그리기 (0) | 2023.06.29 |