toDo.js - 투두리스트 받기 !
👉 html 코드
<form class="js-toDoForm">
<input type="text" placeholder="Write a to do!"/>
</form>
<ul class="js-toDoList"></ul>
👉 js 코드
const toDoForm = document.querySelector(".js-toDoForm"),
toDoInput = toDoForm.querySelector("input"),
toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = "toDos";
let toDos = [];
function deleteToDo(e){
const btn = e.target;
const li = btn.parentNode;
toDoList.removeChild(li);
const cleanToDos = toDos.filter(function(toDo){
return toDo.id !== parseInt(li.id);
});
toDos = cleanToDos;
saveToDos();
};
function saveToDos(){
localStorage.setItem(TODOS_LS, JSON.stringify(toDos));
};
function paintToDo(text){
const li = document.createElement("li");
const delBtn = document.createElement("button");
delBtn.innerText = "❌";
delBtn.addEventListener("click", deleteToDo);
const span = document.createElement("span");
const newId = toDos.length + 1;
span.innerText = text;
li.appendChild(span);
li.appendChild(delBtn);
li.id = newId;
// toDoList.appendChild(li);
// 원페이지에 스크롤 보이지 않게 하기 위해 숫자 제한 : 8개
if(newId < 9){
toDoList.appendChild(li);
}else{
alert("최대 8개까지 작성할 수 있습니다!")
}
const toDoObj = {
text: text,
id: newId
};
// toDos.push(toDoObj);
// 원페이지에 스크롤 보이지 않게 하기 위해 숫자 제한 : 8개
if(newId < 9){
toDos.push(toDoObj);
}
saveToDos();
};
function handleSubmit(e){
e.preventDefault();
const currentValue = toDoInput.value;
paintToDo(currentValue);
// 엔터 누르면 input 안 초기화
toDoInput.value = "";
};
function loadToDos(){
const loadedToDos = localStorage.getItem(TODOS_LS);
if(loadedToDos !== null){
const parsedToDos = JSON.parse(loadedToDos);
parsedToDos.forEach(function(toDo){
paintToDo(toDo.text);
});
}
};
function init(){
loadToDos();
toDoForm.addEventListener("submit",handleSubmit);
};
init();
👉 내가 코드를 작성한 순서
사용 할 객체를 변수로 선언한다.
init 함수를 만든다.
function init(){
};
init()
✍ loadToDos()
function loadToDos(){
const loadedToDos = localStorage.getItem(TODOS_LS);
if(loadedToDos !== null){
const parsedToDos = JSON.parse(loadedToDos);
parsedToDos.forEach(function(toDo){
paintToDo(toDo.text);
});
}
};
localStorage의 TODOS_LS = toDos라는 key값의 value값을 불러온다.
문자열인 그 값을 객체로 변환한다.
JON.parse : 문자열 -> 객체로 변환
JSON 문자열의 구문을 분석하고, 그 결과에서 JavaScript 값이나 객체를 생성한다. <-> JON.stringify와 반대되는 개념!
ex) JSON.parse('null'); // null
문자열 "null" -> null로 변환
forEach : forEach() 메서드는 주어진 함수를 배열 요소 각각에 대해 실행한다.
parsedToDos.forEach(function(toDo){ paintToDo(toDo.text); });
객체로 변환 된 value값들을 forEach함수를 사용하여
✍ paintToDo()
function paintToDo(text){
const li = document.createElement("li");
const delBtn = document.createElement("button");
delBtn.innerText = "❌";
delBtn.addEventListener("click", deleteToDo);
const span = document.createElement("span");
const newId = toDos.length + 1;
span.innerText = text;
li.appendChild(span);
li.appendChild(delBtn);
li.id = newId;
// toDoList.appendChild(li);
// 원페이지에 스크롤 보이지 않게 하기 위해 숫자 제한 : 8개
if(newId < 9){
toDoList.appendChild(li);
}else{
alert("최대 8개까지 작성할 수 있습니다!")
}
const toDoObj = {
text: text,
id: newId
};
// toDos.push(toDoObj);
// 원페이지에 스크롤 보이지 않게 하기 위해 숫자 제한 : 8개
if(newId < 9){
toDos.push(toDoObj);
}
saveToDos();
};
👆 createElement() : 문서에 HTML요소를 추가한다.
createElement(tagName)
ex) const li = document.createElement("li");
👆 createTextNode() : 선택한 요소에 텍스트를 추가한다.
createTextNode( '문자열 입력' )
👆 appendChild() : 선택한 요소 안에 자식 요소를 추가한다.
appendChild(aChild)
ex) toDoList.appendChild(li);
👆 push() <-> pop()
const array1 = [1, 2, 3];
push() : 배열의 마지막부터 요소로 추가
array1.push(4, 5)
// expected output: Array [1, 2, 3, 4, 5]
pop() : 배열의 마지막 요소를 제거
array1.pop()
// expected output: Array [1, 2]
👆 shift() <-> unshift()
const array1 = [1, 2, 3];
array1.shift()
// expected output: Array [2, 3]
array1.unshift(4, 5)
// expected output: Array [4, 5, 1, 2, 3]
const toDoObj = {
text: text,
id: newId
};
toDos = []
toDos.push(toDoObj);
localStorage에도 저장해야하니까
✍ saveToDos()
function saveToDos(){
localStorage.setItem(TODOS_LS, JSON.stringify(toDos));
};
JON.stringify : 객체 -> 문자열로 변환
JSON(JavaScript Object Notation)
local storage에는 자바스크립트의 data를 저장할 수 없다.
string(문자열)으로만 저장이 가능하다. 그래서 object를 string으로 바꿔줘야 한다 !
<-> JON.parse 반대되는 개념!
사용자가 input창에 todoList를 입력해서 엔터를 누르면!
✍ handleSubmit()
function handleSubmit(e){
// 새로고침 방지코드
e.preventDefault();
const currentValue = toDoInput.value;
paintToDo(currentValue);
// 엔터 누르면 input안 초기화
toDoInput.value = "";
};
사용자가 todoList의 delete버튼을 입력하면!
✍ deleteToDo()
function deleteToDo(e){
const btn = e.target;
const li = btn.parentNode;
toDoList.removeChild(li);
const cleanToDos = toDos.filter(function(toDo){
return toDo.id !== parseInt(li.id);
});
toDos = cleanToDos;
saveToDos();
};
👆 e.target : 특정 이벤트를 트리거 한 요소를 가져온다.
내가 쉽게 이해하기로는 제이쿼리의 this를 생각해보았다! => 여러 btn 중 내가 누른 btn!
👆 parentNode : 현재 노드의 부모를 가리킨다.
👆 filter() : 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.
toDoList.removeChild(li);
// const cleanToDos = toDos.filter(function(toDo){
// return toDo.id !== parseInt(li.id);
// });
// 화살표함수로 표현!
const cleanToDos = toDos.filter((toDo) => {
return toDo.id !== parseInt(li.id);
});
👆 화살표함수 : function 표현에 비해 구문이 짧고 자신의 this, arguments, super 또는 new.target을 바인딩 하지 않는다. 화살표 함수는 항상 익명! 함수 표현은 메소드 함수가 아닌 곳에 가장 적합하다. 그래서 생성자로서는 사용할 수 없다.
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// 다음과 동일함: => { return expression; }
매개변수가 하나뿐인 경우 괄호는 선택사항:
(singleParam) => { statements }
singleParam => { statements }
매개변수가 없는 함수는 괄호가 필요:
() => { statements }
👆 parseInt : 문자열 -> 정수로 반환한다.
parseInt(string)
ex) parseInt("42") -> 문자열 "42"를 정수 42로 반환한다. = "null" => null