Vanilla JS로 TO DO LIST 만들기(1)

JU CHEOLJIN·2021년 7월 15일
3

Project

목록 보기
2/9
post-thumbnail

TO DO LIST

프로젝트 소개

제작 기간

2021.07.15 ~ 2021.07.15

사용 기술

  • HTML / CSS
  • JavaScript(ES6+)

구현 사항

1. 기본적인 레이아웃 및 애니메이션 효과.
2. 사용자의 입력을 받아서 + 버튼 클릭 시에 목록에 추가.
3. 사용자의 입력을 받아서 Enter 입력 시에 목록에 추가.
4. 휴지통 버튼 클릭 시에 해당 목록 삭제.

제작하게 된 이유

HTML, CSS를 공부하면서 작은 프로젝트로 자기소개 페이지 만들기(보러가기)를 진행했었다. 이후에 JavaScript 에 대한 공부를 TIL 를 작성하며 진행하고 있다.

처음에는 유튜브에 올라온 엘리님의 강의를 보면서 시작했는데 내용이 좋아서 브라우저101 이라는 강의를 구매해서 듣고 있다. 해당 강의를 듣다보니 항상 실습의 중요성을 강조하고 있었다. 나 역시 강의를 눈으로 듣고 따라 친다고 해서 내 것이 되지 않다는 생각을 강하게 가지고 있었고 최대한 제출된 실습 문제를 강의를 듣기 전에 직접 해결해보려고 했다.

DOM 에 대해서 다룬 강의의 실전 문제로 나온 것이 바로 Shoppin list 만들기였다. 쇼핑리스트를 만드는 것보다는 To do list 가 더 마음에 들었기에 큰 내용의 차이가 없을 것 같아서 내용을 약간 변경하였다.

처음에는 DOMJavaScript 로 조작하는 것이 익숙하지 않아서 막막한 느낌이 들었지만 차근차근 하나씩 문제들을 해결해나가는 기분이 좋았다.

프로젝트 리뷰

기본적인 디자인

디자인은 항상 어렵게 느껴지는 부분이다. 현업에서는 비록 디자이너 분들의 빛이 나는 시안✨ 을 받아서 작업하게 되지 않을까 생각이 들지만 적어도 프론트엔드 개발을 하고 싶다는 생각을 하면서 디자인은 남의 것 이라고 넘겨버리는 것은 불가능한 일인 것 같다.

그래서 열심히 이 사이트, 저 사이트 다니면서 어썸한 시안들을 많이 보려고 노력은 하고 있다. 하지만 이번에도 디자인은 내게 큰 시련을 주었고 엘리 의 프로젝트 소개에 나온 모습을 참고해서 변주를 주었다.

그라데이션 효과나 그림자 등의 효과를 위해 참고할 수 있는 좋은 사이트가 많다는 것에 정말 감사하고 있다. 🙇🏻

사실, HTML / CSS 부분은 기본이라고는 하지만 "이게 최선일까?" 라는 생각을 항상 하게 된다. 내가 한 마크업은 정말로 정보들을 잘 담아낸 Semantic 한 마크업인가 고민이 들고, CSS는 불필요한 property 를 남발하지 않았나 생각이 들고... 🥲 그래서, 리팩토링을 잘 하는 연습도 꼭 필요하다는 생각이 든다.

이제 자바스크립트!

디자인의 산⛰을 넘었으니 이제 동적인 구현을 진행할 차례가 왔다. 제대로 동작하기 위해서는 사용자가 입력한 값을 받아오고, 입력된 값을 이용해서 새로운 리스트를 만들고, 이를 지울 수 있도록 하는 동작이 필요했다. 하나씩 살펴보자.

1. 입력된 값 가져오기 !

const plusButton = document.querySelector(".footer-button");
const items = document.querySelector(".items");
const input = document.querySelector(".footer-input");
// 우선 기본적인 요소들을 할당해주었다.

const addList = () => {
 const inputValue = input.value; // 사용자의 입력 가져오기 
}

사용자의 입력을 가져오는 방법은 간단하다. value 를 사용해서 input 에 입력되어 있는 값을 가져올 수 있었다.

처음에는 addList() 함수의 안이 아닌 전역변수로 inputValue 를 선언하면서 원하는 결과값이 나오지 않아서 당황했다. console.log() 등을 사용하면서 살펴본 결과 전역변수로 inputValue 를 선언해버리면 아무것도 없는 공백의 상태가 계속 나오는 것이 당연함을 알게 됐다. 그래서 이벤트가 발생한 경우에 받아올 수 있도록 addList() 함수 안에 선언을 했다.

2. 새로운 리스트 만들기 !

// addList() 함수 안에 HTML 구조에 맞게 요소들을 만들어 주도록 변수들을 선언했다. 
const itemRow = document.createElement("li");
  itemRow.setAttribute("class", "item-row");

  const item = document.createElement("div");
  item.setAttribute("class", "item");

  const itemContent = document.createElement("span");
  itemContent.setAttribute("class", "item-content");

  const itemDelete = document.createElement("button");
  itemDelete.setAttribute("class", "item-delete");

  const deleteIcon = document.createElement("i");
  deleteIcon.setAttribute("class", "fas fa-trash-alt");

// 만들어진 변수들을 이용해서 구조적 순서에 맞게 메소드를 호출하도록 했다. 
  items.appendChild(itemRow);
  itemRow.appendChild(item);
  item.appendChild(itemContent);
  itemContent.textContent = `${inputValue}`;
  item.appendChild(itemDelete);
  itemDelete.appendChild(deleteIcon);

간단한 동작을 만드는 것임에도 불구하고 꽤나 여러 번 변수를 선언하고 메소드를 호출해야 했다. HTML 구조를 더 엉망으로 작성하였다면 (불필요한 div를 남발한다거나...) 아마 더욱 보기 좋지 않은 코드가 나왔을 것이다. 마크업의 구조도 한번 또 한번 생각하면서 짜자.😮‍💨

간단하게 설명을 덧붙이자면 createElement() 의 경우 HTML 요소를 추가할 수 있고 setAttribute() 는 여기에 클래스를 추가해서 CSS 를 적용할 수 있도록 돕는다. 마지막으로 appendChild() 의 경우에는 선택 된 부모요소의 마지막 자식요소로 parameter 를 생성한다.

3. 플러스 버튼 활성화!

plusButton.addEventListener("click", addList);

이제 우리가 사용할 플러스 버튼에 생명을 불어넣어주면 된다. 이미 함수는 따로 선언을 했기 때문에 콜백함수로 바로 호출해주었다.

addEventListener() 의 경우에는 인자로 event 와 실행하게 될 콜백함수를 받는데 우리는 버튼을 click 할 때 addList() 함수가 실행 되도록 했다. addList() 의 경우에 따로 인자를 받을 필요가 없기 때문에 생략해 주었다.

원하는 동작이 잘 구현됐다. 하지만, 한가지 문제가 있었다. 입력값을 받아서 새 목록을 만들고 나서 입력값을 그대로 남아있었다. 이를 다시 지우고 새 값을 적어야한다면 매우 불편하기 때문에 수정이 필요했다.

input.value = ""; // 새 목록 생성 후에 input initialize

간단한 코드였지만 inputValue 등에 초기화를 하려고 시도하다가 조금 헤맸다. 사실, inputValue 의 경우에 원하는 값을 할당한 것이기 때문에 input.value 를 초기화 하면 되는 간단한 문제였다. DOMJavaScript 로 제어하는 것이 많이 부족하다는 것을 느껴지는 부분이었지만 여러가지 오류 메세지를 보면서 공부가 됐다.

4. 엔터키 활성화!

엔터키를 눌렀을 때도 사용자의 입력값을 받아 새 목록을 만들 수 있도록 하고 싶었다. 그래서 "이건 쉽지!" 하면서 당당하게 아래처럼 코드를 작성했다.

plusButton.addEventListener("keypress", (event) => {
  if (event.key === "Enter") {
    addList();
  }
});

"쉽다며?" 비웃는 것처럼 작동하지 않았다. 생각이 짧았는데, 키 입력에 움직이는 이벤트의 경우에는 당연히 마우스로 클릭이 되는 버튼이 아니라 input 에 이벤트 핸들러를 주는 것이 맞았다. 코드를 잘 작성한 것 같은데 동작하지 않는다면... 특히 console.log() 마저 묵묵부답이라면 불가능한 동작을 시키고 있다는 점을 기억하자. 컴퓨터는 똑똑해서 할 수 있는 건 한다 🤣

5. 휴지통 버튼 활성화!

이번 프로젝트를 진행하면서 가장 어렵게 느껴졌던 부분이었다. 이전의 단계까지는 생각했던 것보다 짧은 시간에 할 수 있었으나 삭제 를 구현하는 부분에 있어서 정말로 많은 시간을 쏟았다.

DOM 을 제어하는 방법들에 대해서 열심히 찾아보면서 다양한 시도를 했지만 스타일링을 위해서 임의로 만들어두었던 더미 목록만 삭제가 됐다. deleteList() 라는 함수를 만들고 전역변수로 deleteButton 를 선언하여 진행하자 첫 번째 요소를 선택하는 querySelector() 는 그대로 진행한 것이다.

parentNode 를 찾아서 사용해보기도 하고 console.log() 도 여러 번 찍어보고, 개발자 도구로 element도 여러 번 뜯어봤지만 답이 쉽게 나오지 않았다. querySelectorAll() 을 사용하면 다 받을 수 있지 않을까 시도를 하기도 하고 배열로 받아볼까 시도도 했지만 빨간 에러메세지만 나를 반겼다. (황당한 시도들 🥲 그만큼 고민을 많이 했다.)

여러 번의 시도 끝에 목록을 생성하는 addList() 함수 안에서 querySelector() 를 사용하면 각 버튼이 원하는 정보를 담고 있음을 알 수 있었다. 그 결과!✨ 이벤트 핸들러를 아예 각 목록이 생성될 때 만들어주면 된다는 것을 발견했다. 유레카!!🌼

itemDelete.addEventListener("click", () => {
    items.removeChild(itemRow);
  });
// 이 짧은 코드가 나를 수없이 놀렸다. 이것도 몰라?

이렇게 작은 토이 프로젝트 중에 하나인 TO DO LIST 만들기가 끝이 났다. 개인적으로 최대한 다른 사람이 만들어낸 코드들은 보지 않으려고 노력했고, 온갖 에러에 시달리다 보니 여러가지 공부를 할 수 있었다. 특히, 이벤트 핸들러나 DOM을 제어하는 것에 대해서 여러가지를 생각해 볼 수 있었다.

이제 남은 것은 바로 리팩토링이다. 과연 엘리님의 경우에는 어떻게 작성했는 지 살펴보고 내가 작성한 코드를 뜯어고쳐보려고 한다. 다음 2편에서 코드를 리팩토링 하는 과정을 기록할 예정이다.💪

완성된 모습!!💪
아직은 부족하지만 곧 가게 될 wecode 에서 다른 분들과 함께 잘 성장해나가면 좋겠다.

profile
사회에 도움이 되는 것은 꿈, 바로 옆의 도움이 되는 것은 평생 목표인 개발자.

0개의 댓글