ToDoList 만들기
JS를 배우고 좀더 이해하고 친숙해지고자 투두 리스트를 만들어 보려고 합니다. 작업은 VSC(Visual Studio Code)로 했습니다. 파일들은 제 github홈페이지 에 저장해 놓을테니 참고해주세요. 이 코드가 꼭 정답이 아닙니다. 더 좋은 코드가 있을 수 있습니다.
앱 디자인 구상
일단 투두 리스트 디자인을 구상해보았습니다. 심플한 디자인을 선호하는 편이라서 깔끔해보이게 디자인을 만들었습니다.
active는 "끝나지 않은 일" 이고 done은 "한 일" 입니다. 입력란에 해야 할 일을 입력하면 active라고 적혀있는 곳 밑에 리스트(active리스트라고 부르겠습니다.)를 출력해줍니다. active항목의 done 버튼을 누르게 되면 active리스트에서 그 항목이 없어집니다. 그리고 done이라고 적혀있는 곳 밑으로 출력됩니다. 또 done항목의 delete 버튼을 누르게 되면 완전히 없어지게 됩니다.
그렇다면 이번 프로젝트에서 구현해야하는 것은
- 입력란에 해야 할 일을 입력하면 active리스트에서 보여준다.
- active항목의 done버튼을 누르면...
- active리스트에서 그 항목을 지운다.
- done리스트에 그 항목을 추가한다.
- done항목의 delete버튼을 누르면 그 항목을 지운다.
이렇게 될 수 있겠네요.
index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>ToDoList</title>
</head>
<body>
<!--주 제목-->
<div class="mainTitle">ToDoList</div>
<!--할일 정보 입력하는 곳-->
<form action="#" class="addToDo" onsubmit="return addActiveList();">
<input type="text" class="addToDoInfo" placeholder="Enter your to-do">
</form>
<!--투두리스트-->
<div class="list">
<!--투두리스트Active-->
<div class="activeToDo">
<div class="activeTitle">Active</div>
<ul type="none" class="listActive">
</ul>
</div>
<!--투두리스트Done-->
<div class="doneToDo">
<div class="doneTitle">Done</div>
<ul type="none" class="listDone">
</ul>
</div>
</div>
</body>
<script type="text/javascript" src="todo.js"></script>
</html>
글씨체는 구글폰트에서 제공하는 Raleway
를 썻습니다. 밑의 코드를 복사해서 <head>
안에 포함시켜서 사용할 수 있습니다.
<link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet">
input란에 값을 타이핑하고 엔터를 누르면 <form>
의 속성값인 onsubmit안에 있는 함수가 호출됩니다.
<!--함수명에 원하는 함수이름을 적으면 됩니다.-->
<form action="" onsubmit="return 함수명">
<input type="text">
</form>
저는 이렇게 코드를 짰습니다. onsubmit안에 있는 함수 addActiveList()
를 실행하면 투두리스트의 active리스트에 들어가게되는겁니다. 조금 이따가 작성할 todo.js에 addActiveList()
를 작성하기로 합시다.
<!--할일 정보 입력하는 곳-->
<form action="#" class="addToDo" onsubmit="return addActiveList();">
<input type="text" class="addToDoInfo" placeholder="Enter your to-do">
</form>
투두 리스트는 아까 말한대로 Active리스트와 Done리스트로 나눌 것이기 때문에 각각 리스트의 형태를 잡아줍시다. 그리고 이 두 개의 리스트를 list라는 클래스로 묶어줍시다.
<!--투두리스트-->
<div class="list">
<!--투두리스트Active-->
<div class="activeToDo">
<div class="activeTitle">Active</div>
<ul type="none" class="listActive">
<!--리스트에 아직 아무것도 넣지 않은 상태입니다.-->
</ul>
</div>
<!--투두리스트Done-->
<div class="doneToDo">
<div class="doneTitle">Done</div>
<ul type="none" class="listDone">
<!--리스트에 아직 아무것도 넣지 않은 상태입니다.-->
</ul>
</div>
</div>
이렇게 html 코드를 다 작성했습니다. 이제 css로 이쁘게 꾸며봅시다.
style.css
:root {
--bg-color: #F1F3F8;
--line-color:#D6E0F0;
--font:'Raleway';
}
/*배경 및 body의 마진, 패딩 세팅*/
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
font-family: var(--font);
}
/*주 제목*/
.mainTitle {
display: flex;
justify-content: center;
font-size: 48px;
font-weight: 600;
padding-top: 48px;
padding-bottom: 72px;
margin: 12px 10%;
border-bottom: 1px solid var(--line-color);
}
/*투두 리스트 입력칸*/
.addToDo {
display: flex;
justify-content: center;
margin-top: 36px;
margin-bottom: 48px;
width: 100%;
}
.addToDoInfo {
width: 70%;
line-height: normal;
padding: 4px;
height: 36px;
font-size: 24px;
}
.addToDoInfo::placeholder {
font-style: oblique;
font-family: var(--font);
color: var(--line-color);
margin: 2px;
}
/*투두 리스트*/
.list {
display: flex;
justify-content: space-around;
width: 100%;
margin: 0 auto;
}
.list .activeToDo, .list .doneToDo {
display: flex;
flex-direction: column;
align-items: center;
width: 50%;
}
.list .activeTitle, .list .doneTitle {
padding: 6px;
border-bottom: 4px solid var(--line-color);
}
.list ul {
padding:0;
margin: 24px;
}
.list li {
display: flex;
justify-content: space-between;
text-align: center;
width: auto;
margin:8px;
padding: 6px;
border-bottom: 2px solid var(--line-color);
}
.list button {
border: none;
background-color: var(--line-color);
font-family: var(--font);
padding: 4px 6px;
margin-left: 12px;
}
기본적으로flex-box
모델을 사용했습니다. :root
에 자주 이용할 색깔을 정의해 줍니다. 저 같은 경우에는color hunt에서 색깔을 골라봤습니다. 그리고 폰트도 --font
로 정의해둡니다.
:root {
--bg-color: #F1F3F8;
--line-color:#D6E0F0;
--font:'Raleway';
}
body의 margin과 padding 값을 모두 0으로 해주고 배경색을 입혀줍니다. 그리고 사용할 폰트도 body 전체에 지정해줍니다.
/*배경 및 body의 마진, 패딩 세팅*/
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
font-family: var(--font);
}
주 제목이나 입력칸을 꾸미는 것은 솔직히 자신이 원하는대로 하시면 됩니다. 저는 약간의 포인트로 주 제목 밑에 선을 추가해 주
었고 입력칸 같은 경우에도 좀 더 크게 바꾸어 보았습니다. 참고해주세요.
/*주 제목*/
.mainTitle {
display: flex;
justify-content: center;
font-size: 48px;
font-weight: 600;
padding-top: 48px;
padding-bottom: 72px;
margin: 12px 10%;
border-bottom: 1px solid var(--line-color);
}
/*투두 리스트 입력칸*/
.addToDo {
display: flex;
justify-content: center;
margin-top: 36px;
margin-bottom: 48px;
width: 100%;
}
.addToDoInfo {
width: 70%;
line-height: normal;
padding: 4px;
height: 36px;
font-size: 24px;
}
.addToDoInfo::placeholder {
font-style: oblique;
font-family: var(--font);
color: var(--line-color);
margin: 2px;
}
리스트에 적용할 css도 포인트로 아래 밑줄을 살짝 넣어주었습니다. 근데 여기에서 li
와 button
에 대해서도 css를 적용한 걸 볼 수 있습니다. todo.js파일에서 알 수 있겠지만 이 두개는 입력칸에 해야 할 일을 적었을 때 li
와 button
태그를 생성해서 리스트에 넣어줄거라 미리 css를 작성해 놓은 것입니다. button
같은경우 새로 폰트를 지정해줘야되서 font-family: var(--font);
를 새로 지정해 주었습니다.
.list li {
display: flex;
justify-content: space-between;
text-align: center;
width: auto;
margin:8px;
padding: 6px;
border-bottom: 2px solid var(--line-color);
}
.list button {
border: none;
background-color: var(--line-color);
font-family: var(--font);
padding: 4px 6px;
margin-left: 12px;
}
이제 js파일을 살펴봅시다.
todo.js
let i = j = 0;
function addActiveList() {
let todovalue = document.querySelector(".addToDoInfo").value;
let li = document.createElement("li");
let button = document.createElement("button");
button.className = "doneBtn" + i;
li.innerHTML = todovalue;
button.innerHTML = "Done";
li.appendChild(button);
document.querySelector(".listActive").appendChild(li);
document.querySelector(".doneBtn"+i).addEventListener('click', doneActive);
document.querySelector(".addToDoInfo").value = '';
i++;
return false;
}
function doneActive() {
let content = this.parentNode;
this.innerHTML = "delete";
this.className = "deleteBtn" + j;
document.querySelector(".deleteBtn"+j).addEventListener('click', deleteDone);
j++;
document.querySelector(".listDone").appendChild(content);
}
function deleteDone() {
this.parentNode.parentNode.removeChild(this.parentNode);
}
함수는 총 3개로 이루어져 있습니다. Active리스트에 해야 할 일을 추가하는 addActiveList()
, Active리스트에 있는 항목을 Done리스트로 옮길 doneActive()
, Done리스트에 있는 항목을 아예 삭제할deleteDone()
이렇게 3개를 구현하면 됩니다.
addActiveList에서는 Active리스트에 새로운 항목을 추가하는 일을 합니다. 일단 어떤 형식으로 추가할까 고민해보다가 다음과 같이 넣으려고 합니다.
<li>해야할일<button class="doneBtn$">Done<button><li/>
<!--여기서 button의 클래스의 '$'는 0이상의 정수를 이야기 합니다.-->
button
의 클래스는 Active리스트에 항목을 추가할 때 마다 클래스명을 달리하려고 합니다.
ex)
<!--첫번째 항목-->
<li>해야할일1<button class="doneBtn0">Done<button><li/>
<!--두번째 항목-->
<li>해야할일2<button class="doneBtn1">Done<button><li/>
<!--세번째 항목-->
<li>해야할일3<button class="doneBtn2">Done<button><li/>
.
.
.
todo.js의 맨 윗줄에 있는 let i = j = 0;
은 이 기능을 위해 만들어 놓은 변수입니다. 자 이제 생성할때마다 클래스의 이름을 달리해야된다는 사실을 인지하고서 addActiveList()
를 봅시다.
addActiveLsit
function addActiveList() {
let todovalue = document.querySelector(".addToDoInfo").value;//.addToDoInfo라는 클래스를 가진 태그의 value값을 가지고 옵니다.
let li = document.createElement("li");//li태그
let button = document.createElement("button");//button태그
button.className = "doneBtn" + i;//button태그에 들어갈 클래스명
li.innerHTML = todovalue;//li에 todovalue를 html(텍스트)로 넣는다.
button.innerHTML = "Done";//button에 "Done"이라는 텍스트를 넣는다.
li.appendChild(button);//li에 button 붙이기, 항목이 완성되었다!
document.querySelector(".listActive").appendChild(li);//리스트에 붙여서 완성된 항목 넣기
document.querySelector(".doneBtn"+i).addEventListener('click', doneActive);//방금 넣은 항목에 대해 버튼을 클릭하면 함수 doneActive를 실행하게함.
document.querySelector(".addToDoInfo").value = '';//input태그에 입력했던 것을 없애줌.
i++;//다음 항목에 추가할 클래스명 맨 뒤에 붙는 숫자. 함수 한 번 마다 1씩 증가하게 해서 모든 항목의 버튼 클래스 명을 모두 다 다르게 한다.
return false;
}
이제 doneActive()
를 살펴보겠습니다. 이 함수의 경우 Active리스트에 있던 항목의 Done 버튼을 누르면 이 항목을 Done리스트로 옮겨주는 역할을 합니다.
doneActive
function doneActive() {
let content = this.parentNode;
//this는 함수가 실행된 바로 그 버튼을 말하므로(이 버튼의 경우 클래스명이 다르므로 그걸로 구분할 수 있다.) 이 버튼의 parentNode는 li태그가 되겠습니다.
this.innerHTML = "delete";
// this 안에 있는 html을 "delete"로 바꿔준다.
this.className = "deleteBtn" + j;
//여기도 마찬가지로 클래스명이 다 다른 버튼 구현을 위해 다음과 같은 형식을 활용했다.
document.querySelector(".deleteBtn"+j).addEventListener('click', deleteDone);
//버튼을 클릭하면 deleteDone함수가 실행되게 이벤트를 걸어준다. 이렇게 done리스트에 알맞은 항목으로 바뀌었다!
j++;
//버큰의 클래스명을 모두 다르게 하기 위해 j를 1씩 증가시킨다.
document.querySelector(".listDone").appendChild(content);
//바뀐 항목을 done리스트에 넣어줍시다.
}
마지막으로 deleteDone()
을 살펴보겠습니다. 이 함수는 Done리스트에 있는 항목의 Delete버튼을 누르면 아예 없애는 역할을 합니다.
deleteDone
function deleteDone() {
this.parentNode.parentNode.removeChild(this.parentNode);
//this의 부모노드의 부모노드인 ul태그 안에 있는 this의 부모 노드를 지웁니다. 즉 this의 li가 지워지게됩니다.
}
이렇게 todolist가 완성되었습니다! 기능이 많은 그런 투두 리스트는 아니지만 순수 자바스크립트만을 이용해서 해보려고 한 자그마한 프로젝트였고, 만족스럽습니다. 글, 코드에 대한 질문이나 피드백,개선 사항이 있다면 말씀해 주세요. 대환영입니다 ㅎㅎ.
'JS' 카테고리의 다른 글
[Vanilla/JavaScript]캘린더 만들기 (0) | 2020.12.18 |
---|---|
[Json/JavaScript]JSON 파싱 및 출력하는 법 (0) | 2020.12.16 |