Javascript를 이용한 Todo-List 만들기
저번 시간에 이어 오늘은 Javascript를 이용해 Todo-List를 만들겠습니다.
어렵지 않습니다.
vanilla javascript 프로젝트와 javascript 입문용으로 많이 활용되는 프로젝트죠.
그럼 시작하겠습니다.
1. 프로젝트 결과물
결과물 링크 : https://tec-motive.github.io/doyun-home/project01/todo-list/index.html
먼저 결과물의 모습입니다.
원하는 문자를 입력하고 추가 버튼을 누르면 일정이 추가되는 구조입니다.
추가된 일정은 ‘일정 완료’,’취소’ 두 가지 버튼을 통해 관리가 가능합니다.
굉장히 단순하죠.
오늘도 html부터 살펴보죠.
2. HTML 구조
<body>
<header>
<h1>DOYUN's Todo List</h1>
</header>
<form>
<input type="text" class="todo-input" />
<button class="todo-button" type="submit">
<i class="fas fa-plus-square"></i>
</button>
<div class="select">
<select name="todos" class="filter-todo">
<option value="all">All</option>
<option value="completed">Completed</option>
<option value="uncompleted">Uncompleted</option>
</select>
</div>
</form>
<div class="todo-container">
<ul class="todo-list"></ul>
</div>
<script src="./app.js"></script>
</body>
매우 단순한 html입니다.
상단에 제목을 담은 해더가 있습니다.
그 아래로 form 태그가 일정을 입력하고 담아둡니다.
입력을 위해 input 태그와 button 태그가 있는 것이 보입니다.
button의 태그는 아이콘을 의미합니다.
‘폰트 어썸’이라는 프로그램을 링크하면 활용 가능합니다.
사실 이 정도가 todo-list를 위한 가장 중요한 정보입니다.
그 하단의 select바는 이번 수업과는 관련이 없는 요소이죠.
selector를 마지막으로 form은 마무리됩니다.
그리고 그 하단에 div에 우리가 작성한 일정이 쌓이는 것이죠.
그럼 일정을 추가, 완료, 삭제하는 todo-list의 javascript를 살펴보겠습니다.
3. Javascript 적용
이제 app.js를 살펴볼 겁니다.
이번에도 역시 3등분으로 나눠 살펴보겠습니다.
Todo-list의 본질적인 요소만 다룰 것입니다.
그러므로 필터관련 정보는 제외하고 설명하겠습니다.
- Selectors
- Event Listners
- Functions
먼저, selector 입니다.
3-1. Selector
//Selector
const todoInput = document.querySelector(".todo-input");
const todoButton = document.querySelector(".todo-button");
const todoList = document.querySelector(".todo-list");
총 개의 변수를 생성했는데요.
먼저 input 바를 의미하는 todoInput을 쿼리셀렉터로 설정해줍니다.
마찬가지로 입력을 위한 todoBotton도 지정합니다.
마지막으로 생성된 일정을 관리할 todoList를 만듦니다.
todoList에 대해선 Event Listner를 통해 더 자세히 알아보겠습니다.
3-2. Event Listener
//Event Listeners
todoButton.addEventListener("click", addTodo);
todoList.addEventListener("click", deleteCheck);
이벤트 리스너는 2가지만 지정해주면 됩니다.
먼저 입력을 위한 버튼에 클릭에 반응해주도록 합니다.
이어서 설정된 todoList를 위한 반응 역시 설정해줍니다.
TodoList에는 deleteCheck함수가 작동합니다.
이 함수는 일정의 완료와 삭제를 제어할 녀석이죠.
여기까지 단순합니다.
함수 부분이 조금 복잡하기 때문에 빠르게 넘어가도록 하죠.
3-3. function
(1) addTodo
function addTodo(event) {
//Prevent form from submitting
event.preventDefault();
//create todo div
const todoDiv = document.createElement("div");
todoDiv.classList.add("todo");
//create LI
const newTodo = document.createElement("li");
newTodo.innerText = todoInput.value;
newTodo.classList.add("todo-item");
todoDiv.appendChild(newTodo);
//CHECK MARK BUTTON
const completedButton = document.createElement("button");
completedButton.innerHTML = '<i class="fas fa-check"></i>';
completedButton.classList.add("completed-btn");
todoDiv.appendChild(completedButton);
//CHECK trash BUTTON
const trashButton = document.createElement("button");
trashButton.innerHTML = '<i class="fas fa-trash"></i>';
trashButton.classList.add("trash-btn");
todoDiv.appendChild(trashButton);
//APPEND TO LIST
todoList.appendChild(todoDiv);
//clear todo input value
todoInput.value = "";
}
총 2개의 함수중 첫 함수인 addTodo입니다.
굉장히 복잡해 보이죠?
그러나 생각보다 어렵지 않습니다.
하나하나 찬찬히 뜯어보도록 하겠습니다.
//Prevent form from submitting
event.preventDefault();
먼저 input 태그가 summit을 하면서 초기화 되는 것을 방지해 줍니다.
Event.preventDefault()를 지정하지 않으면 아마 계속 초기화 될 것입니다.
우리는 일정이 누적되는 것을 보는 것을 원하죠.
이를 위해서 이것을 넣어주는 겁니다.
//create todo div
const todoDiv = document.createElement("div");
todoDiv.classList.add("todo");
//create LI
const newTodo = document.createElement("li");
newTodo.innerText = todoInput.value;
newTodo.classList.add("todo-item");
todoDiv.appendChild(newTodo);
//CHECK MARK BUTTON
const completedButton = document.createElement("button");
completedButton.innerHTML = '<i class="fas fa-check"></i>';
completedButton.classList.add("completed-btn");
todoDiv.appendChild(completedButton);
//CHECK trash BUTTON
const trashButton = document.createElement("button");
trashButton.innerHTML = '<i class="fas fa-trash"></i>';
trashButton.classList.add("trash-btn");
todoDiv.appendChild(trashButton);
다음 거대한 함수의 도막은 모두 createElemet를 가진 것이 보입니다.
이를 이해하기 위해서 잠시 HTML로 돌아가보겠습니다.
<body>
<header>
<h1>DOYUN's Todo List</h1>
</header>
<form>
<input type="text" class="todo-input" />
<button class="todo-button" type="submit">
<i class="fas fa-plus-square"></i>
</button>
</form>
<div class="todo-container">
<ul class="todo-list"></ul>
</div>
<script src="./app.js"></script>
</body>
편의를 위해 selector 부분을 제거했습니다.
html을 보시면 맨 하단에 .todo-container를 가진 div이 보입니다.
Div 내부의 ul에 우리의 일정을 하나씩 추가하는 것이 목표이죠.
추가될 정보를 간략히 보여드리겠습니다.
<div class="todo">
<li class="todo-item"></li>
<button class="completed-btn"></button>
<button class="trash-btn"></button>
</div>
상단의 형식으로 추가되는 것이죠.
앞서 보여드린 함수의 요소는 위의 todo 블럭을 생성해주는 것이죠.
//create todo div
const todoDiv = document.createElement("div");
todoDiv.classList.add("todo");
//create LI
const newTodo = document.createElement("li");
newTodo.innerText = todoInput.value;
newTodo.classList.add("todo-item");
todoDiv.appendChild(newTodo);
함수의 앞부분을 조금 더 자세히 알아볼까요?
div블록과 li 태그를 생성하는 프로세스를 알아보겠습니다.
먼저 변수를 선언해 주는 것은 동일합니다.
변수 선언에는 document.createElement(‘div’)를 통해서 div 블록을 생성하도록 하죠.
그리고 블록을 생성하는 변수에 .classList.add 매소드를 통해서 지정자를 선정해줍니다.
div의 경우는 추가할 것이 없습니다.
다만 하단의 li는 todoDiv에 appendChild해줘야 합니다.
그래야 자식 요소로서 추가되는 것이죠.
Li 하단의 button역시 동일한 프로세스로 생성되기 때문에 생략하겠습니다.
그럼 첫 함수의 마지막 부분을 설명드리겠습니다.
//APPEND TO LIST
todoList.appendChild(todoDiv);
//clear todo input value
todoInput.value = '';
}
위에서 div블록을 생성해주는 프로세스를 todoDiv 변수에 저장했죠.
이 것을 todoList 즉, html의 ul 값의 자식 요소로 추가합니다.
맨 마지막줄의 todoInput.value=’’; 를 추가했는데요.
이는 리스트 등록후 입력창의 정보를 제거해주기 위함입니다.
(2) deleteCheck
function deleteCheck(e) {
const item = e.target;
//delete todo
if (item.classList[0] === "trash-btn") {
const todo = item.parentElement;
//animation
todo.classList.add("fall");
todo.addEventListener("transitionend", function () {
todo.remove();
});
}
//check mark
if (item.classList[0] === "completed-btn") {
const todo = item.parentElement;
todo.classList.toggle("completed");
}
}
두 번째 함수이자 마지막 설명드릴 것은 deleteCheck 함수입니다.
이 함수는 생성된 일정을 완료, 혹은 삭제 할 때 이용됩니다.
앞서 이벤트 리스너에서 deleteCheck는 todoList 변수의 클릭을 통해 활성화 됨을 보았습니다.
즉, ul 영역에 들어가는 모든 일정 부분을 선택하면 작동합니다.
const item = e.target;
가장 먼저 선언되는 변수인 item은 이벤트로 클릭하는 타겟이 할당됩니다.
if (item.classList[0] === "trash-btn") {
const todo = item.parentElement;
//animation
todo.classList.add("fall");
todo.addEventListener("transitionend", function () {
todo.remove();
});
}
그 다음은 item이 타겟팅하는 요소가 trash-btn이면 삭제하는 동작입니다.
item이 할당되는 e.target의 경우 대표하는 class즉 처음 등장하는 class가 trash-btn이면 삭제해야 합니다.
이 때문에 item.classList[0]가 이용되는 것이죠.
그 리고 todo 변수를 통해 버튼의 부모 요소를 선택합니다.
부모 요소가 우리가 없애야하는 일정 리스트인 것이죠.
변수 할당 후에는 애니메이션 효과를 넣었는데요.
리스트가 하강하는 효과를 넣었습니다.
그리고 하강이 마무리되면 그 것을 제거하도록 설정했죠.
if (item.classList[0] === "completed-btn") {
const todo = item.parentElement;
todo.classList.toggle("completed");
}
이제 정말로 마지막인 등록 설정인데요.
item으로 대상을 확인하는 것은 동일합니다.
다만 대상을 삭제하지 않고 클래스 값을 토글(“completed”)로 더해줍니다.
이후에 CSS를 통해서 .completed값에 원하는 효과를 넣으시면 됩니다.
그러면 완료된 행위를 시각적으로 표현 가능하죠.
저는 line through와 opacity 효과를 통해 체크를 표현했습니다.
이로써 todo-list를 간단하게 정리해 봤습니다.
말로 풀려고 하니 어렵네요.
제가 풀어 설명하는 것 보다 코드를 보시면 보다 쉽게 이해가 되실 겁니다.
그럼 다음 시간에 또 뵙겠습니다.
감사합니다.s