TIL - VanillaJS 로 투두리스트(todo-list) 만들기: local Storage 활용

신혜린·2024년 3월 20일
0

TIL

목록 보기
18/19
post-thumbnail

VanillaJS 를 이용해서 간단한 투두리스트를 만드는 방법 기록

index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Todo List w/ vanillaJS</title>
		<link rel="stylesheet" href="index.css" />
	</head>
	<body>
		<div class="todo-container">
			<h1>My Todo List</h1>
			<input type="text" id="todo-input" placeholder="할 일을 추가하세요" />
			<button id="add-todo">+</button>
			<ul id="todo-list"></ul>
		</div>
		<script src="index.js"></script>
	</body>
</html>


index.js

document.addEventListener('DOMContentLoaded', () => {
    const addButton = document.getElementById('add-todo');
    const inputField = document.getElementById('todo-input');
    const todoList = document.getElementById('todo-list');

    addButton.addEventListener('click', function() {
        const todoText = inputField.value.trim();
        if (todoText !== '') {
            const listItem = document.createElement('li');
            listItem.textContent = todoText;
            
            // 삭제 버튼 추가
            const deleteButton = document.createElement('button');
            deleteButton.textContent = 'Delete';
            deleteButton.onclick = function() {
                listItem.remove();
            };
            
            listItem.appendChild(deleteButton);
            todoList.appendChild(listItem);

            inputField.value = ''; // 입력 필드 초기화
        }
    });

    inputField.addEventListener('keypress', function(e) {
        if (e.key === 'Enter') {
            addButton.click(); // Enter 키로 추가 버튼 활성화
        }
    });
});

한 줄씩 뜯어보기

DOMContentLoaded 이벤트 리스너

document.addEventListener('DOMContentLoaded', () => {
  // 코드
});

웹 페이지의 DOM이 완전히 로드되고 파싱되었을 때 실행되어야 하는 스크립트를 감싸는 데 사용.
즉, 안에 있는 코드는 페이지의 HTML이 완전히 로드된 후에 실행되기 시작한다.
이는 HTML 요소에 접근하려고 할 때 해당 요소들이 이미 로드되어 있음을 보장함!

요소 선택

const addButton = document.getElementById('add-todo');
const inputField = document.getElementById('todo-input');
const todoList = document.getElementById('todo-list');

document.getElementById 메소드를 사용해 HTML 파일에서 특정 ID를 가진 요소들을 선택한다.

'Add' 버튼에 클릭 이벤트 리스너 추가

addButton.addEventListener('click', function() {
  //
});

'Add' 버튼(addButton)에 클릭 이벤트 리스너를 추가.
해당 버튼이 클릭될 때마다 입력 필드(inputField)에서 텍스트를 가져와 To-Do 항목을 생성하는 함수가 실행된다.

To-Do 항목 추가

const todoText = inputField.value.trim();
if (todoText !== '') {
  const listItem = document.createElement('li');
  listItem.textContent = todoText;
  
  const deleteButton = document.createElement('button');
  deleteButton.textContent = 'Delete';
  deleteButton.onClick = function() {
    listItem.remove();
  };
  
  listItem.appendChild(deleteButton);
  todoList.appendChild(listItem);
  
  inputField.value=''; // 입력 필드 초기화
}
  1. 사용자가 입력한 텍스트를 trim() 메소드를 사용해 앞뒤 공백을 제거한 후 변수 todoText에 저장한다.
  2. 만약 todoText가 비어있지 않다면(todoText !== ''), 새로운 <li> 요소를 생성하고, 사용자의 입력한 텍스트를 그 내용으로 설정한다.
  3. 각 To-Do 항목에는 삭제 버튼도 포함되어야 하기 때문에 새로운 <button> 요소를 생성하고 'Delete' 라는 텍스트를 넣는다.
  4. 삭제 버튼이 클릭되면 현재 항목(listItem)을 삭제하는 함수를 onClick 이벤트 리스너로 추가한다.(deleteButton.onclick = function() { listItem.remove(); };)
  5. 생성된 삭제 버튼을 <li> 요소에 추가하고(listItem.appendChild(deleteButton)), 이 <li> 요소를 전체 To-Do 리스트(todoList)에 추가한다.(todoList.appendChild(listItem))
  6. 마지막으로 입력 필드를 비워 다음 입력을 위해 준비한다.

Enter 키 입력 이벤트

inputField.addEventListener('keypress', function(e) {
  if (e.key === 'Enter') {
    addButton.click(); // Eneter 키로 추가 버튼 활성화
  }
});

사용자가 입력 필드(inputField)에서 Enter 키를 누르면 'Add' 버튼(addButton)이 클릭되도록 한다.
keypress 이벤트를 감지하고 눌린 키가 'Enter'인 경우에 addButton.click() 을 호출하여 로직을 실행한다.


이렇게 하니까 새로고침 할 때마다 작성한 투두리스트가 삭제되고 초기 상태로 돌아가는 문제가 생겼다. 그래서 local Storage 를 활용해서 새로고침을 해도 투두리스트가 유지되게끔 하는 코드를 새로 추가해주기로 했다.

수정된 index.js

addTodo(), loadTodos(), saveTodos() 추가

document.addEventListener("DOMContentLoaded", () => {
	const addButton = document.getElementById("add-todo");
	const inputField = document.getElementById("todo-input");
	const todoList = document.getElementById("todo-list");

	// 페이지 로드 시 To-do 리스트 로드
	loadTodos();

	addButton.addEventListener("click", function () {
		// 사용자 입력값 투두 리스트 항목 추가
		const todoText = inputField.value.trim();
		if (todoText !== "") {
			addTodo(todoText);
			saveTodos();

			inputField.value = "";
		}
	});

	inputField.addEventListener("keypress", function (e) {
		if (e.key === "Enter") {
			addButton.click();
		}
	});

	function addTodo(todoText) {
		const listItem = document.createElement("li");
		listItem.textContent = todoText;

		// 삭제 버튼 추가
		const deleteButton = document.createElement("button");
		deleteButton.textContent = "X";
		deleteButton.onclick = function () {
			listItem.remove();
			saveTodos(); // 항목을 삭제할 때도 변경사항 저장
		};

		listItem.appendChild(deleteButton);
		todoList.appendChild(listItem);
	}

	// local Storage에서 To-do 리스트 로드
	function loadTodos() {
		const todos = JSON.parse(localStorage.getItem("todos")) || [];
		todos.forEach((todoText) => {
			addTodo(todoText);
		});
	}

	// local Storage에 To-do 리스트 저장
	function saveTodos() {
		const todos = [];
		document.querySelectorAll("#todo-list li").forEach((item) => {
			const todoText = item.textContent.replace("Delete", "").trim();
			todos.push(todoText);
		});
		localStorage.setItem("todos", JSON.stringify(todos));
	}
});

한 줄씩 뜯어보기

addTodo()

 // To-Do 항목을 추가하는 함수
    function addTodo(todoText) {
        const listItem = document.createElement('li');
        listItem.textContent = todoText;

        const deleteButton = document.createElement('button');
        deleteButton.textContent = 'Delete';
        deleteButton.onclick = function() {
            listItem.remove();
            saveTodos(); // 항목을 삭제할 때도 변경사항 저장
        };

        listItem.appendChild(deleteButton);
        todoList.appendChild(listItem);
    }

addButton의 이벤트리스너 안에 있던 로직을 addTodo() 함수로 정의하여 호출한다.

loadTodo()

 // 로컬 스토리지에서 To-Do 리스트 로드
    function loadTodos() {
        const todos = JSON.parse(localStorage.getItem('todos')) || [];
        // 코드
        });
    }

로컬 스토리지에서 'todos'키에 해당하는 값을 가져온다. 저장된 값이 없으면 빈 배열([])을 사용한다.
JSON.parse는 문자열 형태의 데이터를 자바스크립트 객체로 변환시켜준다.

todos.forEach(todoText => {
            addTodo(todoText);
})

todos 배열의 각 항목(todoText)에 대해 addTodo 함수를 호출한다.
이 함수는 새로운 To-Do 항목을 추가한다.

saveTodos()

	// local Storage에 To-do 리스트 저장
	function saveTodos() {
		const todos = [];
		// 코드
	}

새로운 빈 배열 todos를 생성한다. -> 이 배열은 로컬 스토리지에 저장될 To-Do 항목들의 텍스트를 담게 된다.

document.querySelectorAll("#todo-list li").forEach((item) => {
			const todoText = item.textContent.replace("Delete", "").trim();
			todos.push(todoText);
		});

페이지의 모든 To-Do 항목(#todo-list li)을 순회한다.
각 항목의 텍스트 내용에서 'Delete' 문자열을 제거하고 앞뒤 공백을 제거한 뒤, 결과 텍스트(todoText)를 todos 배열에 추가한다.

localStorage.setItem("todos", JSON.stringify(todos));

최종적으로 todos 배열을 JSON 문자열로 변환한 후 'todos' 키를 사용하여 로컬 스토리지에 저장한다.
JSON.stringify는 자바스크립트 객체를 문자열 형태로 변환한다.


💡 이제 새로고침을 해도 local storage에 todos 내용이 저장되어 있기 때문에 투두 리스트 항목이 그대로 유지가 된다!

profile
개 발자국 🐾

0개의 댓글