이번 포스팅에서는 우리가 만드는 애플리케이션의 가장 핵심적인 부분인 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를 통해 객체를 생성한 부분은 클론코딩 과정에서는 처음으로 등장한 부분이라 주목할 필요가 있습니다.

또한 가장 주목해야 할 부분은 ForEachFilter의 사용입니다.

 

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. 결과물

아무것도 없는 모습!
안에 요소가 들어갔다!
하나 더 넣어보았다!
X버튼을 통해 바닐라JS 복습을 지웠다!

지금 발견한 부분인데, 현재 방식대로 만든다면 id값이 중복될 가능성이 생기기 때문에 원하지 않게 같은 id값이 적용되어 삭제될 가능성이 보입니다. 

그렇기 때문에 id값을 부여할 때 보다 확실한 값 (현재 시간이라든지, 절대값을 부여한다든지 등등)을 넣는 것이 좋아보입니다!

 


이제 클론코딩 과정이 거의 끝나갑니다! 마지막까지 열심히 따라가봅시다 :)

반응형
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기