[JavaScript] todo리스트 생성버튼 만들기
in JavaScript on Study
1️⃣ 목표
- 이전에 todo리스트를 class(클래스)로 리펙토링하였습니다.
- 이제 이 todo리스트 클래스가 정상적으로 동작하는지 확인할겸 todo리스트를 여러개 생성하고 지울 수 있는 버튼을 만들어볼 계획입니다.
2️⃣ 상수 선언
(1) 기본적인 방법으로 상수 선언
- 클래스로 리펙토링을 하면서 공통된 상수를 어떻게 선언해야될지 고민이 되었고 다음과 같이 두가지방법을 고려했습니다.
- constructor(생성자)안에서 선언하기
- 클래스밖에서 전역적으로 선언하기
- 첫번째방법은 새로운 개체 인스턴스가 생성될 때마다 고정된 상수를 초기화 해줄 필요가 있을까? 라는 생각이 들었습니다.
- 두번째방법은 class밖에 전역변수로 선언하는 것이 모듈화에 있어서 맞는방법인가? 라는 생각이 들었고, 결정적으로 모듈내에서 이런식으로 선언된 다른 변수들과 변수명 충돌실수를 할 수도 있다는 생각도 들었습니다.
(2) Object.freeze 사용하기
- Object.freeze를 사용하면 위의 문제점들을 해결할 수 있습니다.
- 위와같이 TodoBtn클래스위에 선언해주었습니다.
- TodoBtn클래스를 export default대신에 export로 굳이 바꿔줬는데 그 이유는 다음의 사이트가 설명을 잘해주기 때문에 넘기겠습니다.
👉🏻👉🏻👉🏻 모듈 내보내고 가져오기 - JAVASCRIPT.INFO 🍄
- Object.freeze의 기능 또한 다음의 사이트에서 설명이 잘되어 있습니다.
👉🏻👉🏻👉🏻 Object.freeze() - mozillaMDN 🍄
- 위의 MDN의 내용대로라면 상수로써 역할을 하기에 충분할 것같습니다. 추가적으로 개체형태이기 때문에 사용할 때도 편리해집니다.
- 개체명만 입력하면 VScode에서 알아서 목록들을 보여줍니다.
- 이런식으로 만들어준 상수 개체들을 한 파일에 따로 모아서 사용해도 괜찮을 것(?) 같다는 생각이 들었습니다.
3️⃣ todoBtn클래스 만들기
(1) 이벤트 구성
eventMaster = (event) => {
if (event.target.className === "plus__Btn") {
this.addPage(event);
} else if (event.target.className === "delete__page") {
this.deletePage(event);
} else if (event.target.classList.contains("todo__Btn")) {
this.viewPage(event.target.id);
}
};
- todoBtn클래스의 이벤트는 다음과 같습니다.
- plus 버튼: todo리스트를 생성해주는 버튼
- delete 버튼: todo리스트를 삭제해주는 버튼
- 개별todo리스트 버튼: 버튼에 맞는 todo리스트를 보여주는 버튼
(2) 데이터 저장
- todoBtn클래스는 생성한 todo리스트의 id만 저장하면 됩니다. (각각의 todo 내용은 todo리스트클래스가 저장하고 있기 때문에)
- 아직 백엔드지식이 없기 때문에 todo리스트를 만들었을 때처럼 local storage를 이용했습니다.
👉🏻👉🏻👉🏻 todo리스트 만들기포스트 🍄
(3) todoBtn 주요기능함수 구현
- plus 버튼을 누르면 다음의 순서로 함수가 호출됩니다.
- addPage(): todo리스트의
id
생성 밑 local storage에 데이터를 저장하는 역할 - makePage(): 새로운 todo리스트인스턴스 생성 및 page배열에 각todo리스트정보 저장 (page배열은 특정todo리스트를 노출시키고자 할때 이용할 배열)
- makeBtn(): 각 todo리스트와 매칭되는 버튼을 생성해주는 역할
- addPage(): todo리스트의
[1] addPage()
addPage() {
this.checkPlusBtn();
if(this.savedPage.length > BtnUI.max_button) {
return ;
}
const num = Date.now();
const todoNode = {
id: `todo${num}`,
nb: num,
}
this.makePage(num);
this.savedPage.push(todoNode);
this.saveData();
}
[2] makePage()
makePage(num) {
this.setHide();
const nb = `${num % BtnUI.color_count}`;
const newForm = document.createElement("form");
newForm.setAttribute('class', `todo__page color${nb}`);
newForm.setAttribute('id', `todo${num}`);
this.todoMaster.appendChild(newForm);
const tempForm = document.querySelector(`form[id="todo${num}"]`);
const newTodo = new Todo(tempForm, num, nb);
const newPage = {
fm: tempForm,
nb: num,
}
this.page.push(newPage);
this.makeBtn(num);
this.checkPlusBtn();
}
[3] makeBtn()
makeBtn(num) {
const newBtn = document.createElement("span");
const nb = `${num % BtnUI.color_count}`;
const colorClass = `color${nb}`;
newBtn.setAttribute('id', `todo${num}`);
newBtn.innerHTML = `
<button class="todo__Btn ${colorClass}" id="todo${num}">
</button>
<button class="delete__page" id="todo${num}">
X
</button>
`;
this.BtnZone.append(newBtn);
}
(4) 데이터 불러오기
- 각각의 todo리스트내용들은 todo리스트클래스가 local storage에 저장해두었습니다.
- todoBtn클래스가 local storage에 저장한 todo리스트의
id
를 불러와서 addPage()호출을 건너 뛰고 makePage()함수부터 호출하여 생성해 주었습니다.
loadData() {
const savedData = localStorage.getItem(BtnUI.page_key);
if (savedData !== null) {
const parseData = JSON.parse(savedData);
this.savedPage = parseData;
parseData.forEach((obj) => this.makePage(obj.nb));
}
}
(5) 타이틀입력(prompt이용)
- todo클래스에 title을 입력받는 기능이 있는데도 불구하고 귄찮아서.. 위의 이미지와 같이 단순히 숫자만 나오게 구현을 했었습니다. (이 숫자는 단순히 랜덤한 버튼색에 배정된 숫자)
- 현재구현한 버튼색은 23가지인데 언제가는 중복되는 숫자가 나오게 되므로 todo클래스 title입력 기능도 이용하기로 했습니다. (현재 23가지 색조합(배경색, 글씨색)을 일리리 구현했는데 이러한 것도 자동적으로 랜덤한 조합으로 만들어준다면 좋을 것 같다는 생각(?)이 들었습니다.)
- todo클래스에서는 받아온 title인자를 위와 같이 처리하기 때문에
innerHTML
사용으로 생길 수 있는 보안문제로 부터 안전합니다. (textContent로 한번 파싱한 후 사용, 효율적인 방법인지는 모르겠음..) - 그렇기 때문에 title를 prompt()를 이용하여 유저로 부터 직접 입력을 받아도 될 것 같습니다.
- plus버튼을 누르면 호출되는 addPage()에 위와 같이 유저입력을 받는 코드를 넣었습니다. 이 데이터는 새로고침할 때도 문제없이 출력되어야하기 때문에 “local storage”에도 저장해 주었습니다.
4️⃣ 보안해야할 점
(1) 로딩 매커니즘
- 새로고침을 할때마다 todo리스트 폼을 생성해주고 todo리스트 내용을 입력해주고, 각 todo리스트 버튼을 생성해줍니다.
- 아직 생성할 노드가 적기 때문에 느껴지지 않지만 생성할 노드가 무수히 많아진다면 매우 비효율적이라는 생각이 들었습니다.
- 곧 백엔드에 대한 공부도 시작할 계획인데 좀 더 지식과 경험을 쌓고 다시한번 고민해야봐야할 것 같습니다.