๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

javascript

250313 to-do ๋ฆฌ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ (1)

 

์ฑŒ๋ฆฐ์ง€์—์„œ ์‹ฌํ™”๊ณผ์ œ (๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€, ์ฒดํฌ๋ฐ•์Šค)๋ฅผ  ์ถ”๊ฐ€ํ•œ ๊ธ€์ด๋‹ค.

 

 

ํ•„์ˆ˜ ์กฐ๊ฑด
  1. index.html์— ์žˆ๋Š” input ์š”์†Œ์— ์ž…๋ ฅ๋œ ๊ฐ’(value)๊ณผ button ์š”์†Œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
  2. ์ƒˆ๋กœ์šด li ์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  input ์š”์†Œ์— ์ž…๋ ฅ๋œ ๊ฐ’์„ textContent๋กœ ๊ฐ–๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  3. li ์š”์†Œ๋Š” ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น li ์š”์†Œ๊ฐ€ ์ง€์›Œ์ง€๋Š” delete ๋ฒ„ํŠผ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 
  4. ์ž…๋ ฅ์ฐฝ์€ ์ดˆ๊ธฐํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  5. ๋งŒ์•ฝ ์ž…๋ ฅ์ฐฝ์— ์•„๋ฌด๊ฒƒ๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ alert๋กœ ์œ ์ €์—๊ฒŒ ์ž…๋ ฅ์„ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  6. 3.์˜ ์‚ญ์ œ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ ๐Ÿ”ฝ
const deleteBtn = document.createElement('button'); 
deleteBtn.onclick = function () {
	this.parentElement.remove(); 
};

 

์‹ฌํ™” ๋„์ „ ๊ณผ์ œ
  1. ์ž…๋ ฅํ•œ TO-DO๊ฐ€ Local Storage์— ์ €์žฅ๋˜์–ด ์ƒˆ๋กœ ๊ณ ์นจ ํ›„์—๋„ ์œ ์ง€๋˜๋„๋ก ํ•ด๋ณด์„ธ์š”.
  2. ํ•  ์ผ ํ•ญ๋ชฉ์— ์™„๋ฃŒ ํ‘œ์‹œ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด์„ธ์š”.
  3. TO-DO ๋ฆฌ์ŠคํŠธ๋ฅผ ๋“œ๋ž˜๊ทธ์•ค๋“œ๋กญ์œผ๋กœ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ ์šฉํ•ด ๋ณด์„ธ์š”.

 

 


 

 

https://stackblitz.com/edit/vitejs-vite-cqztxjtt?embed=1&file=script.js&theme=dark

 

JavaScript 5์ผ์ฐจ (67%) (forked) - StackBlitz

๊ธฐ๋ณธ ์กฐ๊ฑด + ์ฒดํฌ๋ฐ•์Šค ๊ธฐ๋Šฅ

stackblitz.com

 

์ผ๋‹จ ๊ธฐ์กด ํ‹€์„ ๊ฑฐ์˜ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ  ๊ธฐ๋ณธ ์กฐ๊ฑด + ์‹ฌํ™” 2๋ฒˆ (์ฒดํฌ๋ฐ•์Šค)๊นŒ์ง€๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

์ฝ”๋“œ ๐Ÿ”ฝ 

 

index.html

๋”๋ณด๊ธฐ
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>ํ•  ์ผ ๋ชฉ๋ก</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="todo-container">
      <div id="inputbox">
        <input type="text" id="todo-input" placeholder="ํ•  ์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”" />
        <button id="add-btn">์ถ”๊ฐ€</button>
      </div>
      <ul id="todo-list"></ul>
    </div>
    <script src="script.js"></script>
  </body>
</html>

 

style.css

๋”๋ณด๊ธฐ
body {
  font-family: Arial, sans-serif;
}

ul {
  list-style: none;
  padding: 0;
}

.todo-container {
  max-width: 400px;
  margin: auto;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 5px;
}

#inputbox {
  display: flex;
  justify-content: space-between;
}

#todo-input {
  width: 70%;
  padding: 10px;
  margin-right: 5px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

#add-btn {
  width: 30%;
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  white-space: nowrap;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

#add-btn:hover {
  background-color: #0056b3;
}

#todo-list {
  margin-top: 20px;
}

#todo-list li {
  cursor: pointer;
  padding: 10px;
  border-bottom: 1px solid #ddd;
  display: flex;
  align-items: center;
}

#todo-list li > span {
  width: 100%;
  margin-left: 5px;
}

#todo-list li:last-child {
  border-bottom: none;
}

.delete-btn {
  margin-left: auto;
  background-color: red;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
  white-space: nowrap;
}

 

script.js

๋”๋ณด๊ธฐ
// 1. index.html์— ์žˆ๋Š” input ์š”์†Œ์— ์ž…๋ ฅ๋œ ๊ฐ’(value)๊ณผ button ์š”์†Œ๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
const todoInput = document.getElementById('todo-input');
const todoList = document.getElementById('todo-list');
const addBtn = document.getElementById('add-btn');

// 0. ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ์ด๋ฒคํŠธ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
addBtn.addEventListener('click', function () {
  // trim() : ๊ณต๋ฐฑ์„ ์ง€์›Œ์ฃผ๋Š” ํ•จ์ˆ˜๋กœ value์˜ ๊ฐ’์œผ๋กœ "     "์ด ๋“ค์–ด์™”์„ ๋•Œ ๋“ฑ์˜ ๊ณต๋ฐฑ์œผ๋กœ๋งŒ ๊ตฌ์„ฑ๋œ ํ• ์ผ ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค. 
  if (todoInput.value.trim() !== '') {
  
    // 2. ์ƒˆ๋กœ์šด li์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  
    const li = document.createElement('li');
    
    // ์‹ฌํ™”2) ํ•  ์ผ ํ•ญ๋ชฉ์— ์™„๋ฃŒ ํ‘œ์‹œ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด์„ธ์š”.
    // ์ฒดํฌ๋ฐ•์Šค ์ถ”๊ฐ€
    const checkBtn = document.createElement('input');
    checkBtn.type = 'checkbox';
    li.append(checkBtn);
    
    // change ์ด๋ฒคํŠธ : ์ฒดํฌ๋ฐ•์Šค์ผ ๋•Œ๋Š” ์ฒดํฌํ•˜๊ฑฐ๋‚˜ ํ•ด์ œํ•  ๋•Œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ๋‹ค. 
    checkBtn.addEventListener('change', function () {
      // checked : ํ•ด๋‹น ์ฒดํฌ๋ฒ„ํŠผ์˜ ์†์„ฑ์œผ๋กœ checked๊ฐ€ ๋ถ™์—ˆ์„ ๋•Œ 
      if (checkBtn.checked) {
      	// nextElementSibling : ๋ถ€๋ชจ์˜ ์ž์‹ ๋ชฉ๋ก์—์„œ ์ง€์ •๋œ ์š”์†Œ(์ฒดํฌ๋ฒ„ํŠผ) ๋ฐ”๋กœ ๋’ค์— ์žˆ๋Š” ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜
        this.nextElementSibling.style.textDecoration = 'line-through';
      } else {
        this.nextElementSibling.style.textDecoration = '';
      }
    });

	// 2. input ์š”์†Œ์— ์ž…๋ ฅ๋œ ๊ฐ’์„ textContent๋กœ ๊ฐ–๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    // ํ• ์ผ ๋‚ด์šฉ ์ถ”๊ฐ€
    const todoContent = document.createElement('span');
    todoContent.textContent = todoInput.value;
    li.append(todoContent);

    // 3. li ์š”์†Œ๋Š” ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น li ์š”์†Œ๊ฐ€ ์ง€์›Œ์ง€๋Š” delete ๋ฒ„ํŠผ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    // deleteBtn ์ถ”๊ฐ€
    const deleteBtn = document.createElement('button');
    // ๋ฒ„ํŠผ์— ๊ฐ„๋‹จํ•˜๊ฒŒ css ์ ์šฉ์„ ํ•˜๊ธฐ์œ„ํ•ด ํด๋ž˜์Šค ๋ถ€์—ฌ
    deleteBtn.className = 'delete-btn';
    deleteBtn.textContent = '์‚ญ์ œ';
    li.append(deleteBtn);
    deleteBtn.onclick = function () {
      // this.parentElement : ์ด ๊ฐ์ฒด์˜ ๋ถ€๋ชจ ์š”์†Œ (์ฆ‰ deleteBtn์ด ํด๋ฆญ๋œ ๋ถ€๋ชจ liํƒœ๊ทธ)
      this.parentElement.remove();
    };

    // li๋ฅผ ul(#todo-list)์—์ถ”๊ฐ€
    todoList.append(li);

    // 4. ์ž…๋ ฅ์ฐฝ์€ ์ดˆ๊ธฐํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    todoInput.value = '';

  
  } else {
    // 5. ๋งŒ์•ฝ ์ž…๋ ฅ์ฐฝ์— ์•„๋ฌด๊ฒƒ๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ alert๋กœ ์œ ์ €์—๊ฒŒ ์ž…๋ ฅ์„ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    alert('๋‚ด์šฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!');
    return;
  }
});

 

* ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ฒดํฌํ•  ๋•Œ์˜ ์ด๋ฒคํŠธ๋Š” change์ด๋‹ค.
change ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์ž์„ธํ•œ ๋‚ด์šฉ์€ : https://developer.mozilla.org/ko/docs/Web/API/HTMLElement/change_event 

 

์ด์ œ ์‹ฌํ™” 1๋ฒˆ, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋ ค๋‹ˆ ์ฝ”๋“œ๋ฅผ ์ข€ ๋œฏ์–ด๋‚ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์ƒ๊ฒผ๋‹ค.

 

๊ธฐ์กด ์ฝ”๋“œ์—์„œ๋Š” add-btn์„ ํด๋ฆญํ•œ ๋’ค์— ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๊ฐ€ ๋˜๊ณ , ์ถ”๊ฐ€๋œ ํ•ญ๋ชฉ์„ ์‚ญ์ œ / ์ฒดํฌ๊ฐ€ ๊ฐ€๋Šฅํ–ˆ๋‹ค๋งŒ ์ง€๊ธˆ๊นŒ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ด ํŽ˜์ด์ง€๋Š” ์–ด์ฐจํ”ผ ์ƒˆ๋กœ๊ณ ์นจ ํ•˜๋ฉด ๋‚ด์šฉ์ด ์ „๋ถ€ ์‚ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์—, ๊ธฐ๋Šฅ๋“ค์„ ํ…Œ์ŠคํŠธํ•ด ๋ณด๋ ค๋ฉด ๊ผญ ํ•œ ๋ฒˆ์€ ํ•  ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด add-btn์„ ํด๋ฆญํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด์ œ ์ถ”๊ฐ€ํ•œ ๋ชฉ๋ก๋“ค์„ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ธฐ, ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์žˆ๋Š” ๋‚ด์šฉ์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ๋ฅผ ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋‚ด ๋‚ด์šฉ๋“ค์„ ์ข€ ๋‚˜๋ˆ ์•ผ ํ–ˆ๋‹ค.

 


 

script.js ๐Ÿ”ฝ

๋”๋ณด๊ธฐ
const toDocontainer = document.getElementById("todo-container");
const todoInput = document.getElementById("todo-input");
const todoList = document.getElementById("todo-list");
const addBtn = document.getElementById("add-btn");

// ใ€€๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ
const todoStorage = JSON.parse(localStorage.getItem("todoStorage"));
if (todoStorage !== null) {
  for (let i = 0; i < todoStorage.length; i++) {
    // todoStorage์˜ [i]๋ฒˆ์งธ ๊ฐ’์„ makeToDoList์— ๋„ฃ์–ด๋‘ 
    makeToDoList(todoStorage[i]);
  }
}

// add-btn ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ
addBtn.addEventListener("click", function () {
  if (todoInput.value.trim() !== "") {
    makeToDoList();
  } else {
    alert('๋‚ด์šฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.')
  }
});

// ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ ํ•จ์ˆ˜
function makeToDoList(storageList) {
  const li = document.createElement("li");
  const checkBtn = document.createElement("input");
  const todoContent = document.createElement("span");
  const deleteBtn = document.createElement("button");

  // local storage์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด
  if (storageList) {
    todoInput.value = storageList.contents;
    if (storageList.check === true) {
      li.classList.add("checked");
      checkBtn.checked = true;
    }
  }

  // ์ฒดํฌ๋ฐ•์Šค ์ถ”๊ฐ€
  checkBtn.type = "checkbox";
  li.append(checkBtn);
  checkBtn.addEventListener("change", function () {
    // toggle("ํด๋ž˜์Šค๋ช…") : ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ์ œ๊ฑฐ ํ›„ false๋ฅผ ๋ฐ˜ํ™˜, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ถ”๊ฐ€ ํ›„ true ๋ฐ˜ํ™˜
    this.parentElement.classList.toggle("checked");
  });

  // ํ• ์ผ ๋‚ด์šฉ ์ถ”๊ฐ€
  todoContent.textContent = todoInput.value;
  li.append(todoContent);

  // deleteBtn ์ถ”๊ฐ€
  deleteBtn.className = "delete-btn";
  deleteBtn.textContent = "์‚ญ์ œ";
  li.append(deleteBtn);
  deleteBtn.onclick = function () {
    this.parentElement.remove();
  };

  // li ์ถ”๊ฐ€
  todoList.append(li);

  // input์ฐฝ ์ดˆ๊ธฐํ™”
  todoInput.value = "";

}

// ใ€€๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ ์ €์žฅํ•˜๊ธฐ ๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ
document.getElementById("saveStorage").addEventListener("click", function () {
  // localStorage์— ๋‹ด์„ array
  const todoStorage = [];
  for (let i = 0; i < todoList.children.length; i++) {
    const todoObject = {
      contents: todoList.children[i].querySelector("span").textContent,
      // classList.contains("ํด๋ž˜์Šค๋ช…") : ํ•ด๋‹น ํด๋ž˜์Šค ๋ช…์ด ํ•ด๋‹น ์š”์†Œ์— ํฌํ•จ๋˜์–ด์žˆ๋Š”์ง€
      check: todoList.children[i].classList.contains("checked"),
    };
    todoStorage.push(todoObject);
  }
  console.log(todoStorage);
  // JSON.stringfy() : ๋ณ€์ˆ˜๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ”๊ฟ” array ๊ทธ ์ž์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋งŒ๋“ ๋‹ค.
  localStorage.setItem("todoStorage", JSON.stringify(todoStorage));
});

 

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ์ €์žฅ / ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์™ธ์—๋Š” ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง„ ์ ์€ ์—†์œผ๋‚˜, ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์‹œ์—๋„ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ์„ ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋กœ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•ด ์ฃผ๋ฉด์„œ ๋ฐ”๋€Œ๊ฒŒ ๋œ ์ ์ด ์žˆ๋‹ค.

 

 


 

 

1. addBtn์„ ๋ˆŒ๋ €์„ ๋•Œ (ํ•  ์ผ์„ ์ถ”๊ฐ€ํ•  ๋•Œ)์˜ ํ•จ์ˆ˜ ๋ถ„๋ฆฌ

 

์ˆ˜์ • ์ „

const addBtn = document.getElementById('add-btn');

addBtn.addEventListener('click', function () {
  if (todoInput.value.trim() !== '') {
    const li = document.createElement('li');
    // ....... ์ƒ๋žต ........
    todoList.append(li);
    todoInput.value = '';
  } else {
    alert('๋‚ด์šฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!');
  }
});

 

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋Œ€๋กœ, add-btn์„ ํด๋ฆญํ•œ ๋’ค์— ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋˜๊ณ  ์žˆ๋Š” ๋ชจ์Šต์ด๋‹ค.

์ด ์ด๋ฒคํŠธ๋กœ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์—๋Š” todoList์˜ ์ž์‹ ๋ชฉ๋ก๋“ค์„ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ์ฝ”๋“œ๊ฐ€ ๋‹ค ๋‹ด๊ฒจ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์ถœ๋ ฅ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•ด๋‹น ๋‚ด์šฉ์ด ๊ฑฐ์˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค.

์ด ๋‚ด์šฉ์„ ๋‹ด์„ ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ addBtn์„ ํด๋ฆญํ•  ๋•Œ, ๋˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

 

 

์ˆ˜์ • ํ›„

// local Storage์—์„œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
const todoStorage = JSON.parse(localStorage.getItem("todoStorage"));
if (todoStorage !== null) {
  for (let i = 0; i < todoStorage.length; i++) {
    // todoStorage์˜ [i]๋ฒˆ์งธ ๊ฐ’์„ makeToDoList์— ๋„ฃ์–ด๋‘ 
    makeToDoList(todoStorage[i]);
  }
}
// add-btn ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ
addBtn.addEventListener("click", function () {
  if (todoInput.value.trim() !== "") {
    makeToDoList();
  } else {
    alert('๋‚ด์šฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
  }
});

// ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ ํ•จ์ˆ˜
function makeToDoList(storageList) {
  const li = document.createElement("li");
  // local storage์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด
  if (storageList) {
    todoInput.value = storageList.contents;
    if (storageList.check === true) {
      li.classList.add("checked");
      checkBtn.checked = true;
    }
  }
  // .....์ƒ๋žต......
  
  todoList.append(li);
}

 

 

๊ณต๋ฐฑ ์ž…๋ ฅ ์‹œ ํ•  ์ผ์ด ์ถ”๊ฐ€ ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” if else๋ฌธ์„ addBtn ํด๋ฆญ ์‹œ์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด์— ์ž‘์„ฑํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ๋ชจ๋‘ makeToDoList ํ•จ์ˆ˜์— ๋“ค์–ด์žˆ์–ด ํ˜ธ์ถœํ•˜๋ฉด ์–ธ์ œ๋“ ์ง€ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋๋‹ค.

๋‹ค๋งŒ ์ด์ „๊ณผ ๋‹ฌ๋ฆฌ ํ•จ์ˆ˜์— ํŒŒ๋ผ๋ฏธํ„ฐ storageList๊ฐ€ ์ƒ๊ฒผ๋Š”๋ฐ, ์—†์œผ๋ฉด if(storageList){}๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

* if(storageList) : storageList๊ฐ€ 1 ์ด์ƒ์ธ์ง€(์ฆ‰ true์ธ์ง€)๋ฅผ ์กฐ๊ฑด์œผ๋กœ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์—†๋‹ค๋ฉด false๊ฐ€ ๋˜์–ด ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์ด ์‹คํ–‰๋œ๋‹ค.

 

 

์ฒดํฌ๊ฐ€ ๋˜์–ด์žˆ์œผ๋ฉด check : true, ๋˜์–ด์žˆ์ง€ ์•Š์œผ๋ฉด check : false์ด๋‹ค.

 

local Storage์—์„œ ์ €์žฅ๋œ ํ˜•ํƒœ๋Š” key๊ฐ’ todoStorage์˜ value๊ฐ€ {'ํ•  ์ผ(contents)', '์ฒดํฌ ์œ ๋ฌด(check)'}์˜ ํ˜•ํƒœ์˜ ์›์†Œ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐฐ์—ด๋กœ ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค.

์ด ๋•Œ ๋ฐฐ์—ด์— ์žˆ๋Š” ๊ฐ’์„ ๋ชจ๋‘ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด for๋ฌธ ์•ˆ์— makeToDoList() ๋ฉ”์†Œ๋“œ์— todoStorage[i]๋ฅผ ์ธ์ž๋กœ ๋„ฃ์–ด ์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— if (storageList) {} ๋ถ€๋ถ„์ด ์‹คํ–‰๋œ๋‹ค. ์ด ๋•Œ if๋ฌธ ๋‚ด์— ์žˆ๋Š”  if (storageList.check === true) {} ์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜ 2. ์ฒดํฌ๋ฐ•์Šค์— ์„œ์ˆ ํ–ˆ๋‹ค.

 

 

* local storage ๊ฐœ๋… ์ฐธ๊ณ 

Mdn : https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage

๋งน์ˆ˜๋‹˜์˜ ๋ธ”๋กœ๊ทธ : https://myeongsu0257.tistory.com/130

 

๊ทธ ์™ธ์—๋„ 2๋…„์ „์— ๊ฐ•์˜ ๋“ค์–ด๋ณด๋ฉด์„œ local storage๋ฅผ ํ™œ์šฉํ•ด Todo list๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋Š” ์‹ค์Šต์„ ํ–ˆ์—ˆ๋Š”๋ฐ ๊ฐ™์€ ํˆฌ๋‘ ๋ฆฌ์ŠคํŠธ์ธ๋งŒํผ ์œ ์‚ฌํ•œ ์ ์ด ๋งŽ์•„ ๋งํฌ๋ฅผ ๋‚จ๊ฒจ๋‘”๋‹ค.

 

todo list ๊ธฐ๋ณธ ๊ธฐ๋Šฅ + local storage์— ์ €์žฅ(์ถ”๊ฐ€ํ•˜๋ฉด ๋ฐ”๋กœ ์ €์žฅ์ด ๋จ) ๋ฐ ์ถœ๋ ฅ : https://hydeveloper.tistory.com/71

todo list local storage์—์„œ๋„ ํ• ์ผ ์‚ญ์ œ : https://hydeveloper.tistory.com/72

 

 

 


 

 

2. ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ์ €์žฅ

 

์ฃผ์„์œผ๋กœ๋„ ๋ฉ”๋ชจํ•ด๋’€๊ณ  ์ €์žฅ ๊ธฐ๋Šฅ ๋˜ํ•œ ์ด ๊ธ€์—์„œ ๋‹ค๋ค˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์„ธํ•œ ์„ค๋ช…์€ ํŒจ์Šคํ•œ๋‹ค... 

// ใ€€๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ ์ €์žฅํ•˜๊ธฐ ๏ฝฅ๏พŸ*๏ฝก๏ฝฅ ๏ฝก*๏ฝฅ๏พŸ
document.getElementById("saveStorage").addEventListener("click", function () {
  // localStorage์— ๋‹ด์„ array
  const todoStorage = [];
  for (let i = 0; i < todoList.children.length; i++) {
    const todoObject = {
      contents: todoList.children[i].querySelector("span").textContent,
      // classList.contains("ํด๋ž˜์Šค๋ช…") : ํ•ด๋‹น ํด๋ž˜์Šค ๋ช…์ด ํ•ด๋‹น ์š”์†Œ์— ํฌํ•จ๋˜์–ด์žˆ๋Š”์ง€
      check: todoList.children[i].classList.contains("checked"),
    };
    todoStorage.push(todoObject);
  }
  console.log(todoStorage);
  // JSON.stringfy() : ๋ณ€์ˆ˜๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ”๊ฟ” array ๊ทธ ์ž์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋งŒ๋“ ๋‹ค.
  localStorage.setItem("todoStorage", JSON.stringify(todoStorage));
});

 


 

 

3. ์ฒดํฌ๋ฐ•์Šค 

 

์ˆ˜์ • ์ „

addBtn.addEventListener('click', function () {
    const li = document.createElement('li');
    const checkBtn = document.createElement('input');

    checkBtn.type = 'checkbox';
    li.append(checkBtn);
    checkBtn.addEventListener('change', function () {
      if (checkBtn.checked) {
        this.nextElementSibling.style.textDecoration = 'line-through';
      } else {
        this.nextElementSibling.style.textDecoration = '';
      }
    });
});

 

 

addBtn์— 'click'์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ์ถœ๋ ฅ๋˜๊ฒŒ ํ–ˆ๋‹ค.

์ด๋Š” ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ๋‹จ์ˆœํžˆ ์ฒดํฌ๋ฐ•์Šค์˜ ๊ธฐ๋Šฅ๋งŒ ํ•˜๋Š” ์ •๋„๋‹ค.

 

์ฒดํฌ๋ฐ•์Šค์˜ ์ฒดํฌ ๋ถ€๋ถ„์ธ checkBtn์— 'change'์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ,

๋ฒ„ํŠผ์ด ์ฒดํฌ๋๋‹ค๋ฉด(checkBtn.checked) ์ฒดํฌ๋ฒ„ํŠผ์˜ ๋‹ค์Œ ์š”์†Œ๊ฐ€ ๋  spanํƒœ๊ทธ์˜ ์Šคํƒ€์ผ์„ textDecoration = 'line-through'๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ฒดํฌ๋œ ํ•ญ๋ชฉ์— ์ทจ์†Œ์„ ์„ ๊ทธ๋ฆฌ๊ฒŒ ํ–ˆ๋‹ค.

 

 

์•„๋ž˜๋Š” ์ˆ˜์ • ํ›„์˜ ์ฝ”๋“œ๋‹ค.

// ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ ํ•จ์ˆ˜
function makeToDoList(storageList) {
  const li = document.createElement('li');
  const checkBtn = document.createElement('input');
  
  // local storage์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด
  if (storageList) {
    todoInput.value = storageList.contents;
    // ์œ„์˜ if(storageList)์ฒ˜๋Ÿผ if(storageList.check)์œผ๋กœ ์จ๋„ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•œ๋‹ค
    if (storageList.check === true) {
      li.classList.add("checked");
      checkBtn.checked = true;
    }
  }
  checkBtn.type = 'checkbox';
  li.append(checkBtn);
  checkBtn.addEventListener('change', function () {
    // toggle("ํด๋ž˜์Šค๋ช…") : ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ์ œ๊ฑฐ ํ›„ false๋ฅผ ๋ฐ˜ํ™˜, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ถ”๊ฐ€ ํ›„ true ๋ฐ˜ํ™˜
    this.parentElement.classList.toggle('checked');
  });
}

 

 

์ฒดํฌ๋ฒ„ํŠผ์€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์ˆ˜์ •๋œ ๋‚ด์šฉ์ด ๊ฝค ์žˆ๋‹ค.

 

1) checkBtn์„ ๋ˆŒ๋ €์„ ๋•Œ์˜ ์ด๋ฒคํŠธ ๋‚ด์šฉ

์ˆ˜์ • ์ „์—๋Š” ๋ฐ”๋กœ ๋’ค ํ˜•์ œ ์š”์†Œ์—๊ฒŒ ์Šคํƒ€์ผ์„ ์ ์šฉํ–ˆ๋‹ค๋ฉด, ์ด๋ฒˆ์—” Local Storage์—๋„ check ์œ ๋ฌด๋ฅผ ํŒ๋ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ์ฒดํฌ๋ฒ„ํŠผ์˜ ๋ถ€๋ชจ ์š”์†Œ(li)์—๊ฒŒ checked๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด add()๋ฉ”์†Œ๋“œ ์จ๋„ ๋˜๋Š”๋ฐ toggle()๋ฉ”์†Œ๋“œ๋ฅผ ์™œ ์ผ๋ƒ

์ฃผ์„์— ์ ์–ด๋‘” ๋Œ€๋กœ, ๋‹จ ํ•œ์ค„๋กœ ํ•ด๋‹น ๋ถ€๋ชจ์š”์†Œ์—๊ฒŒ checked๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€ ์ด๋ฏธ ์žˆ๋Š” ์ƒํƒœ๋ผ๋ฉด checked ํด๋ž˜์Šค๋ฅผ ์—†์• ์ฃผ๋ฉฐ, ๋งŒ์•ฝ ์—†๋Š” ์ƒํƒœ๋ผ๋ฉด checked๋ฅผ ์ถ”๊ฐ€ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. 

 

๊ทธ๋ ‡๋‹ค๋ฉด ์Šคํƒ€์ผ์€ ์–ด๋–ป๊ฒŒ ๋๋ƒ, ๊ทธ๊ฑด css ํŒŒ์ผ์„ ์ˆ˜์ •ํ–ˆ๋‹ค.

#todo-list li.checked > span {
  text-decoration: line-through;
}

 

์•„๊นŒ๋ถ€ํ„ฐ ์™œ ํ˜•์ œ ์š”์†Œ๋งŒ ๊พธ๋ฉฐ์ฃผ๋ƒ๋ฉด

 

 

์œ„ ์ด๋ฏธ์ง€์™€ ๊ฐ™์ด ๊ทธ๋ƒฅ ๋ถ€๋ชจ๋ฅผ ๊พธ๋ฉฐ์ค„ ๊ฒฝ์šฐ, ์˜†์— ์žˆ๋Š” ์‚ญ์ œ๋ฒ„ํŠผ๊นŒ์ง€ ๋ฐ‘์ค„์ด ๊ทธ์–ด์ง€๋Š”๋ฐ ๋ณด๊ธฐ๊ฐ€ ์•ˆ์ข‹์•„์„œ span ํƒœ๊ทธ๋งŒ ๊พธ๋ฉฐ์ฃผ๊ณ  ์žˆ๋‹ค... 

 

 

2) if (storageList.check === true) {}

์œ„์˜ 1. ์—์„œ ์ถ”๊ฐ€๋œ if(storageList){}๋ฌธ ์•ˆ์— ์žˆ๋Š” ์กฐ๊ฑด์ด๋‹ค. ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•  ๋•Œ ๊ธฐ์กด์— ์ €์žฅ๋˜์–ด์žˆ๋˜ storageList value์— ๋‹ด๊ธด ๋ฐฐ์—ด์˜ ์›์†Œ๊ฐ€ {contents, check}์˜ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ์—ˆ๋Š”๋ฐ, ์ด ๋•Œ check์˜ ๊ฐ’์„ booleanํ˜•์œผ๋กœ ๋ฐ›์•˜๋‹ค.

๋•Œ๋ฌธ์— check๊ฐ€ true๋ผ๋ฉด ํ•ด๋‹น li์˜ checked ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š”๋ฐ, ๋ฌธ์ œ๋Š” ์œ„์˜ 1)์—์„œ ์–ธ๊ธ‰ํ•œ ์ด๋ฒคํŠธ์™€๋Š” ๋‹ฌ๋ฆฌ ์ง€๊ธˆ ํ•ด๋‹น li ์•ˆ์— ์žˆ๋Š” checkBtn์— ์ง์ ‘์ ์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— checkBtn.checked = true;๋ฅผ ์ถ”๊ฐ€ํ•ด ํ•ด๋‹น li์˜ ์ฒดํฌ๋ฐ•์Šค์˜ checked ์†์„ฑ์„ true๋กœ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. 

 

 


 

 

์ฐธ๊ณ 

local storage์—์„œ ๋ฆฌ์ŠคํŠธ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ณผ์ •์€ https://velog.io/@seoyaon/Javascript-Todo-List-%EB%A7%8C%EB%93%A4%EA%B8%B0 ์„ ๋ณด๊ณ  ๋งŽ์ด ์ฐธ๊ณ ํ–ˆ๋‹ค... ์ง„์งœ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค