이번 포스팅에서는 우리가 만드는 애플리케이션의 가장 핵심적인 부분인 ToDoList입니다.
가장 어려운 부분이기도 하니 주석을 잘 참고하셔서 이해하시면 좋겠습니다!!
본 내용은 바닐라 JS로 크롬 앱 만들기의 3.4~3.6 부분 강의에 대한 내용정리입니다!
목차
0. index.html
toDoList를 작성하는 부분과 출력하는 부분, 총 2가지가 추가되었습니다.
별도로 이모지 출력 문제때문에 mata charset="uft-8"을 추가한 부분이 눈에 띄네요.
ul, form과 같은 html 관련 내용은 설명하지 않고 넘어갑니다!
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Something</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1> <!-- 임시로 -->
</div>
<form class="js-form form"> <!-- 작성창용 css를 적용하기 위해 class를 2개로!! form을 통해 엔터를 누를 때마다 정보가 전달!! -->
<input type="text" placeholder="What is your name?" /> <!-- 입력창 추가 -->
</form>
<h4 class="js-greetings greetings"></h4>
<!-- 할 일을 작성하는 부분 -->
<form class="js-toDoForm">
<input type="text" placeholder="Write a to do" />
</form>
<!-- 이 부분에 toDoList안에 들어갈 내용들이 출력된다 -->
<ul class="js-toDoList">
</ul>
<script src="clock.js"></script>
<script src="greeting.js"></script>
<script src="todo.js"></script>
</body>
</html>
1. todo.js
if문을 사용한 조건문을 통해 할 일이 있다면 출력하고, 없으면 출력하지 않는 기능과 form을 통해 새로운 ToDoList를 작성할 수 있는 기능을 만들었습니다. 그리고 ToDoList에 내용을 추가했으니 이미 존재하는 List들에 대해 삭제하는 기능도 만들었습니다.
본 내용은 앞에서 만든 내용들의 복습과 간단한 응용수준이지만, toDoObj를 통해 객체를 생성한 부분은 클론코딩 과정에서는 처음으로 등장한 부분이라 주목할 필요가 있습니다.
또한 가장 주목해야 할 부분은 ForEach와 Filter의 사용입니다.
forEach는 배열의 각 요소에 대해 한번씩 순서대로 매개변수로 받은 함수를 실행합니다.
filter는 배열 내 각 요소에 대해 매개변수로 들어간 함수에 대해 true를 반환하는 모든 값이 있는 새로운 배열을 반환합니다.
그리고 두 함수의 매개변수로 함수가 들어가는데, 본 클론코딩 과정에서는 function(toDo)를 이용해 매개변수가 들어갈 자리에서 임시로 함수를 만들었습니다. 실제로 밖에서 함수를 만들고 사용해도 똑같이 작동합니다.
자세한 내용은 아래 코드와 주석으로 갈음합니다! 잘 모르겠다고 생각되는 부분은 댓글로 남겨주시거나, VanillaJS 크롬 앱 클론코딩 수강생이시라면 강의영상에 댓글로 남겨주시면 친절하게 답변해 주실겁니다 ㅎㅎ
// todo.js
const toDoForm = document.querySelector(".js-toDoForm"),
toDoInput = toDoForm.querySelector("input"),
toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = 'toDos'; // LocalStorage에 toDos라는 저장소를 만든다!
let toDos = []; // 할 일을 모아놓은 배열(array) - toDos는 계속해서 변하기 때문에 const가 아닌 let으로 만들어야한다!!
function deleteToDo(event){ // localStorage에서 요소를 지우기 위한 함수
// TMI : 요소의 부모를 알기 위해서는 console.dir()!
const btn = event.target; // 이벤트가 일어난 장소를 알려주는 .target!!
const li = btn.parentNode; // btn의 부모노드를 li에 저장
toDoList.removeChild(li); // toDoList에서 li라는 요소를 가진 친구를 지운다!
const cleanToDos = toDos.filter(function(toDo){
return toDo.id !== parseInt(li.id); // toDo.id와 li.id를 비교해서 다른것만 toDos에 저장!!
// parseInt는 string을 int로 바꿔주기 위함! li.id는 string이기 때문에 정확한 비교를 위해서는 int 형태로 바꿔줘야한다.
});
// filter는 배열 내 각 요소에 대해 매개변수로 들어간 함수에 대해 true를 반환하는 모든 값이 있는 새로운 배열을 반환한다!
toDos = cleanToDos // 삭제해야할 요소를 지우고 새롭게 만든 배열을 다시 toDos에 할당!!
saveToDos(); // 삭제 작업을 마쳤으니 이제 localStorage에 새로 바꾼 내용을 저장!
}
function saveToDos(){ // localStorage에 요소를 저장하기 위한 함수
localStorage.setItem(TODOS_LS, JSON.stringify(toDos)); // localStorage에 저장! 자바스크립트는 localStorage에 있는 모든 데이터를 string으로 저장하려고 한다는 점을 꼭 생각하자!! 그렇기에 object를 string으로 바꿔서 저장한다.
// JSON.stringify는 자바스크립트 object를 string으로 바꿔준다! 이거의 반대는 parse()!!
// JSON은 JavaScript Object Notation의 준말! 데이터를 전달할 때 자바스크립트가 그걸 다룰 수 있또록 object로 바꿔주는 기능!!
}
function paintToDo(text){ // 화면에 할 일을 출력하는 함수
const li = document.createElement("li"); // 비어있는 li를 하나 만든다
const delBtn = document.createElement("button"); // 버튼을 하나 만든다
const span = document.createElement("span"); // span(공간)을 하나 만든다
const newId = toDos.length + 1; // li와 밑에 만든 toDoObj객체에 id값을 부여하기 위해!
delBtn.innerHTML = "❌" // https://kr.piliapp.com/emoji/list/ 여기서 이모티콘 가져옴!!
// innerHTML은 element 안의 HTML이나 XML을 가져오고, innerTEXT는 text값만을 가져온다.
// 이건 직접 가져와서 html코드를 입력해보면, innerText는 코드가 그대로 출력되지만 innerHTML은 html이 적용되어서 출력된다!!
delBtn.addEventListener("click", deleteToDo); // delBtn을 누르면 deleteToDo 함수가 실행!!
span.innerText = text; // span에는 받아온 text를 넣는다
li.appendChild(delBtn); // 만든 li에 delBtn(X표시)를 넣는다
li.appendChild(span); // 만든 li에 span(입력창에 적혀있던 text를 바로 위 innerText에서 넣었다!!)을 넣는다
li.id = newId; // li에도 id를 부여
toDoList.appendChild(li); // 만든 li를 toDoList(3번 라인에서 .jstoDoList에서 가져온 그거 맞다!)에 넣는다
const toDoObj = { // 객체를 하나 만들어서 toDos에 저장
text: text, // text는 그대로 text
id: toDos.length + 1 // id는 현재 toDos의 길이 + 1 (이러면 id값이 1부터 들어가게 된다!)
};
toDos.push(toDoObj); // array에 PUSH하기!
saveToDos(); // localStorage에 저장하기!! 반드시 push 이후에 해야 정상적으로 저장된다!
}
function handleSubmit(event){ // 엔터키가 눌리면 작동되는 함수
event.preventDefault(); // 기본 동작(새로고침)을 없애주는 함수 - event를 사용하기 때문에 handleSubmit의 매개변수로 event를 받아와서 사용한다
const currentValue = toDoInput.value; // 작성된 값을 받아온다
paintToDo(currentValue); // 그 값을 화면에 출력한다
toDoInput.value = ""; // 엔터키를 누르고 나면 작성창 안을 비운다
}
function loadToDos(){ // 해야할 일을 띄우는 함수
const loadedToDos = localStorage.getItem(TODOS_LS); // localStorage에서 TODOS_LS에 있는 값을 가져온다 (이게 할 일)
if(loadedToDos !== null){ // 할 게 있다면
const parsedToDos = JSON.parse(loadedToDos); // string을 object로 변환하는 parse!
// 모든 parsedToDos 안의 요소들을 paintToDo를 통해 출력해줘야한다
parsedToDos.forEach(function(toDo){
paintToDo(toDo.text);
});
// forEach는 array에 담겨있는 것들에 대해 각각 한번씩 함수를 실행시킨다! 안에 파라미터값으로 함수가 들어간다!! 안에서 함수를 만들어서 사용하였다.
// parsedToDos 안의 요소들이 하나하나씩 toDo 자리에 들어가게 되고, 그 요소들 안에 들어있는 text가 paintToDo의 매개변수가 된다.
}
}
function init(){
loadToDos(); // 해야할 일을 불러온다!
toDoForm.addEventListener("submit", handleSubmit); // 할 일 form에 무언가가 제출되면 handleSubmit 함수를 작동
}
init();
2. 결과물
지금 발견한 부분인데, 현재 방식대로 만든다면 id값이 중복될 가능성이 생기기 때문에 원하지 않게 같은 id값이 적용되어 삭제될 가능성이 보입니다.
그렇기 때문에 id값을 부여할 때 보다 확실한 값 (현재 시간이라든지, 절대값을 부여한다든지 등등)을 넣는 것이 좋아보입니다!
이제 클론코딩 과정이 거의 끝나갑니다! 마지막까지 열심히 따라가봅시다 :)
최근댓글