노마드코더 JS 6, 7강

이안이다·2023년 5월 10일
0

JavaScript

목록 보기
5/6
post-thumbnail

6강 코드 간단 정리 후 7장 이론

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="css/style.css" />
    <title>Momentum App</title>
  </head>
  <body>
    <form class="hidden" id="login-form">
      <input
        required
        maxlength="15"
        type="text"
        placeholder="What is your name?"
      />
      <input type="submit" value="Log In" />
    </form>
    <h2 id="clock">00:00:00</h2>
    <h1 class="hidden" id="greeting"></h1>
    <div id="quote">
      <span></span>
      <span></span>
    </div>
    <script src="js/greetings.js"></script>
    <script src="js/clock.js"></script>
    <script src="js/quotes.js"></script>
  </body>
</html>

js/quotes.js 파일을 아래와 같이 작성

const quotes = [
  {
    quote: "The way to get started is to quit talking and begin doing.",
    author: "Walt Disney",
  },
  {
    quote: "Life is what happens when you're busy making other plans.",
    author: "John Lennon",
  },
  {
    quote:
      "The world is a book and those who do not travel read only one page.",
    author: "Saint Augustine",
  },
  {
    quote: "Life is either a daring adventure or nothing at all.",
    author: "Helen Keller",
  },
  {
    quote: "To Travel is to Live",
    author: "Hans Christian Andersen",
  },
  {
    quote: "Only a life lived for others is a life worthwhile.",
    author: "Albert Einstein",
  },
  {
    quote: "You only live once, but if you do it right, once is enough.",
    author: "Mae West",
  },
  {
    quote: "Never go on trips with anyone you do ntot love.",
    author: "Hemmingway",
  },
  {
    quote: "We wander for distraction, but we travel for fulfilment.",
    author: "Hilaire Belloc",
  },
  {
    quote: "Travel expands the mind and fills the gap.",
    author: "Sheda Savage",
  },
];

const quote = document.querySelector("#quote span:first-child");
const author = document.querySelector("#quote span:last-child");
const todaysQuote = quotes[Math.floor(Math.random() * quotes.length)];

quote.innerText = todaysQuote.quote;
author.innerText = todaysQuote.author;

7강.

7.0 Setup

이제 지금까지 공부했던 내용들 기반으로 본격적인 todolist를 만들거다. 아자아자

<script src="js/todo.js"></script>

일단 todo.js라는 파일 하나 더 src폴더 안에다 만들어놓고 index.html에 script연결을 해주자.


이 화면에서 입력을 하고 엔터하면 submit이벤트 발생하면서 새로고침 되는데 그거 막기 위해서!?

function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = toDoInput.value; //비어있는 값을 변수에 다시 복사하는 것 뿐 변수의 기존 값이 없어지는 게 아니라는 것 명심
  toDoInput.value = "";
  paintToDo(newTodo);
}

이렇게 코드 추가해서 submit해도 새로고침 되지 않게 할 수 있고, 엔터를 누를 때마다 입력창이 비워지게 하기 위해서 toDoInput.value="";를 추가했다. 비우기 위한 코드다. 근데 명심할 건, 비웠다고 해서 newTodo의 값이 없어진 건 아니다. newTodo라는 변수에 비어있는 값을 복사했을 뿐 !

자 이번에는 paintTodo()라는 함수를 구현할거다.

function paintToDo(newTodo) {
  const li = document.createElement("li");
  const span = document.createElement("span");
  span.innerText = newTodo;
  const button = document.createElement("button");
  button.innerText = "❌";
  button.addEventListener("click", deleteToDo);
  li.appendChild(span);
  li.appendChild(button);
  toDoList.appendChild(li);
}

const li는 일단 꼭 li라는 이름으로 변수명을 지을 필요는 없음. 근데 "li"태그를 만들 때 사용할 변수인건데 이해하기 쉽게 하기 위해서 li라고 변수명을 지은 것임. span도 마찬가지 !


입력란에 hello라고 치고 엔터치면 console에는 아무것도 없다가 이렇게 li과 span이 만들어지는 걸 확인할 수 있다.

li태그와 span태그를 만들었고, span을 li 내부로 집어 넣었고, 텍스트를 span 내부에 넣은거지. 그리고 그 텍스트는 사용자가 form에서 나한테 준 newTodo값인거고 ! 그리고 새로운 li를 list(toDolist)에 추가해주게끔 코드를 짠거다. 그리고 지우는 기능을 구현하기 위해 button태그를 만들었고 button의 텍스트에 "X"을 innerText해줬어. 버튼도 li에 추가해줬어. 버튼을 click했을 때 삭제가 될 수 있게 addEventListener("click", deleteToDo)를 만들어줬고 deleteTodo()라는 함수는 아래와 같이 구현하면 됨.

function deleteToDo(event) {
  const li = event.target.parentElement;
  li.remove();
}

자, 그리고 click이 발생한 target을 정확히 모를 수 있는데 f12열어서 겁나 여러개의 프러퍼티들 중에서 path를 확인해보면 button이 타겟이 되고 있다는 걸 알 수 있음. 그래서 deleteToDo()를 이렇게 구현해준 거다. button의 부모노드인 li를 삭제해야 내가 추가한 그 리스트를 삭제 할 수 있는거니깐.


자 여기까지 했으면 일단 추가하고 삭제하는 기능까지는 완성이 됐는데 문제는 새로고침하면 내용들이 다 날아가버린다는 점이야. 이럴 땐 Local Storage에 저장하면 됨.

예를 들어 이렇게 a,b,c를 입력했을 때 다음 두 가지의 과정이 중요해.

  1. 입력된 a,b,c를 local storage에 저장한다.
  2. 새로고침 후에 local storage로부터 저장했던 내용들을 다시 불러온다.

먼저 저장을 하기 위해서 새로운 배열과 함수를 만들자.

const toDos = [];

function saveToDos() {
  localStorage.setItem("todos", JSON.stringify(toDos));
}

local storage에는 텍스트형식만 저장할 수 있고 배열은 저장할 수 없었잖아? 근데 이렇게 JSON.stringify를 쓰면 내가 입력창에 입력한 것 그대로 텍스트화 시켜서 저장할 수 있게 해줌 !!! 매우 유용하니까 꼭 기억하장.

JSON.stringify( ) 메모 메모 메모


여기까지 하면 이제 내가 입력창에 입력한 todo내용이 문자열화돼서 그대로 local storage에 저장까지 잘 된다. 근데 로컬저장소에는 저장이 되는데 화면에는 나타나지 않는다. 그래서 새로고침을 하면 내용이 다 날아간 것 처럼 보임!! 이번에는 그걸 해결해보자.

if (savedToDos !== null) {
  const parsedToDos = JSON.parse(savedToDos);
  parsedToDos.forEach((item) => console.log("this is the turn of ", item));
}

일단 입력창에서 입력 받은 값이 null일 수도 있으니깐, 그게 아닌 경우에 대해서만 실행하게끔 조건문 걸어두고 이렇게 코드를 짰다.

forEach()는 괄호 속 함수를 실행시켜주는데, parsedToDos가 array잖아? 그 array에 있는 각각의 item에 대해서 실행시켜준다. 즉, parsedToDos에 있는 각각의 item에 대해서 console.log를 해주겠다는 뜻이다.

중요한 건, 내가 지금 어떤 item을 사용하고 있는지 모른다면 결국 무용지물이라는 것 !


자 슬슬 끝나가는데..
일단 내가 todos에 작성한게 로컬저장소에 잘 저장되고 새로고침해도 없어지지도 않게끔 잘 만들었다. 근데 문제가 생겼다 !! X버튼을 눌러서 리스트를 삭제해도 로컬저장소에는 그대로 남아있어서 새로고침을 하면 다시 나타난다는 점이다. 이를 해결하기 위해 다음과 같이 코드를 작성하자.

--> date()와 random을 이용해서 내가 입력한 각각의 todos들에 id를 부여하고 이를 통해서 원하는 내용을 로컬저장소에서 완전히 삭제하는 기능을 구현할 수 있다.

다음은 최종적으로 모든 기능을 구현한 todo.js 코드이다.

const toDoForm = document.getElementById("todo-form");
const toDoInput = document.querySelector("#todo-form input");
const toDoList = document.getElementById("todo-list");

const TODOS_KEY = "todos";

let toDos = [];

function saveToDos() {
  localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

function deleteToDo(event) {
  const li = event.target.parentElement;
  li.remove();
  toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
  saveToDos();
}

function paintToDo(newTodo) {
  const li = document.createElement("li");
  li.id = newTodo.id;
  const span = document.createElement("span");
  span.innerText = newTodo.text;
  const button = document.createElement("button");
  button.innerText = "❌";
  button.addEventListener("click", deleteToDo);
  li.appendChild(span);
  li.appendChild(button);
  toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = toDoInput.value;
  toDoInput.value = "";
  const newTodoObj = {
    text: newTodo,
    id: Date.now(),
  };
  toDos.push(newTodoObj);
  paintToDo(newTodoObj);
  saveToDos();
}

toDoForm.addEventListener("submit", handleToDoSubmit);

const savedToDos = localStorage.getItem(TODOS_KEY);

if (savedToDos !== null) {
  const parsedToDos = JSON.parse(savedToDos);
  toDos = parsedToDos;
  parsedToDos.forEach(paintToDo);
}
profile
경제와 개발을 곁들인 기획자..!

0개의 댓글