-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[2주차 기본/심화 과제] WEB 💛 TO DO MATE 🌈 없애보자!!!!! #5
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와 은서야 정말 고생많았다 ~
특히 드래그 드롭이나 SPA로 구현한 부분은 배워갈 점이 너무 많았어!
SPA쪽은 폴더 구성이라도 좀 더 찬찬히 보려고.
함수 명세에 관한 부분/ 주석 관련한 부분에서도 다음 과제 때 참고해야할 정도로
코드리뷰하기 넘 좋았어!
최고 최고 갓은서
localStorage.getItem("todo_data") === null && | ||
localStorage.setItem("todo_data", JSON.stringify(TODO_DATA)); //localStorage 초기화 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if문 대신 연산자 쓴 거 참고해야겠다 ㅎㅎ
listToTodo(todoData); | ||
checkDone(); | ||
todoCount(); | ||
checkModal(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 되면 윈도우가 로드될 때마다 위 함수가 실행되는 거 아닌가요?!
나는 로드될 때 데이터만 업데이트하는 식으로 했는데
이렇게 해준 이유가 궁금행
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
으음 윈도우가 로드될 때마다 로컬스토리지에서 값을 가져와서 화면에 뿌리고, 완료된 할일수 체크하고, 모달이 작동하게하는 저 일련의 함수들이 모두 실행되어야 작동이 되더라구... 데이터만 업데이트한다면 저 필요한 기능들이 작동을 하질 않는달까..? 사실 나도 사실 무지성 코딩하느라 그냥 돌아가게 하는데 혈안이었네 ㅠㅠ
const addBtn = document.getElementsByClassName("add-btn"); | ||
const addBtnList = [...addBtn]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
querySelectorAll 대신 이걸 쓴 이유가 궁금합니다!
바로 배열로 만들어주려고 그런건가?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 안그래도 이 과제하면서 querySelectorAll과 getElementBy...의 차이점에 대해 알아봤었는데
이 글 보니까 일반적으로 후자가 더 빠르다는? 말에 이걸 쓴거같아~ 개인적으로 저 메소드가 습관이 되기도 했다
}); | ||
}); | ||
|
||
curModalFor || resolveModal(modal); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
연산자를 적재적소에 잘 쓴다 굳굳 참고해야겠어~~
list.forEach((category) => { | ||
let filteredItem = localStorageData.filter( | ||
(item) => item.category === category | ||
)[0]; | ||
newData.push({ | ||
category: filteredItem.category, | ||
list: filteredItem.list, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forEach와 filter를 정말 잘 활용한다 ~~
특히 로컬스토리지 데이터는 다루기가 좀 복잡하다고 느꼈는데,
가독성 좋게 짠 것 같아 ㅎㅎ
배워갑니다 굳
animation: bounce 1s ease infinite; | ||
} | ||
|
||
@keyframes bounce { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
바운시 바운시를 이렇게 구현했군!
귀여워 ㅋㅋ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
두 번째 과제도 넘넘 수고많았어!!!!! :)
todoCount(); | ||
checkModal(); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 이렇게 정리해주니까 넘 깔끔하고 좋다!!!!😍🤩
const doneBtn = document.getElementsByClassName("done-btn"); | ||
const doneBtnList = [...doneBtn]; //HTMLCollection to Array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요거는 const doneBtnList = Array.from(document.getElementsByClassName("done-btn")); 요렇게 쓰면 한 줄로 쓸 수 있을 것 같다!!! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 맞아 array로 바꾸는 방법이 .from을 포함해서 여러가지가 있었는데 웬만하면 한줄에 끝내는게 더 깔끔하겠구나!
const doneBtn = document.getElementsByClassName("done-btn"); | ||
const doneBtnList = [...doneBtn]; //HTMLCollection to Array | ||
|
||
doneBtnList.forEach((item) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기 반복 인자는 item 이라고 쓰기보다, doneBtnList 의 개별 요소를 뜻하는 doneBtn 으로 써주면 더 가독성 있는 코드가 좋을 것 같아!!! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
호곡 그러게 그냥 item이 제일 무난해서 그렇게 매번 썼었는데 의미를 담는게 더 좋겠다!!!
localStorageData | ||
.find((item) => item.category === changedCategory) | ||
.list.find((item) => item.content === changedTodo).done = false; | ||
item.attributes.done.value = "false"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기 setAttribute 를 통해 수정해주면 더 가독성 있을 것 같다!!! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호!!! setAttribute기억할게!!! 돌아돌아 갔군..
let todoContent = todoTemplate.cloneNode(true); //템플릿 복사 | ||
let todoNewHtml = todoContent.innerHTML; //템플릿 안의 html 복사 | ||
|
||
todoNewHtml = todoNewHtml //복사한 html에서 필요한 부분을 item 내용에 맞게 변경 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기서 둘 다 const 로 변경하구 todoNewHtml은 innerHTML.replace 로 붙여써주면 더 좋을 것 같다!! 그리구 newTodoContent newTodoHtml 로 변수명을 바꿔주는 건 혹시 어떻게 생각해?? ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 좀더 명확한 변수명@@ 조언 고마우
const form = document.getElementById("add-todo__form"); | ||
//form이 제출됐을 때 | ||
form.addEventListener("submit", (e) => { | ||
e.preventDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
완전 꼼꼼미!!!!
🔗 구현 페이지
위 배포 페이지는 SPA가 아닙니다! vite로 만든 SPA도 github pages로 배포할 수 있는 방법이 따로 있던데 시간 관계상,,, 다음에 해보는 걸로! 😙
✨ 구현 기능 명세
기본 과제
할일 목록 데이터
하트 안의 숫자
카테고리별 할일 추가
달력 / MY 버튼 클릭시 페이지 이동
심화 과제
카테고리별 할일 추가
Vanilla JS로 SPA 구현하기 (요거 구현해놨었는데 PR에서 빠져있었네요ㅜㅜ 뒤늦게 추가)
My 페이지 Drag & Drop
🌼 PR Point
JS to SPA
먼저 1주차처럼 기본 html, css, js로만 구현한게 week2 폴더에 있고, 이걸 vite를 이용해서 SPA로 바꾼 것은 week2-SPA 폴더에 있습니다!
데이터 구성
1번 과제와는 다르게 상수 데이터를 어떤 식으로 구성할 것인가에 대해서도 굉장히 고민이 많아지더라구요... 이걸 카테고리 별로 나눠야할지? 아니면 할 일 목록별로 나눠야할지? 그리고 카테고리 박스 별 색상을 상수 데이터 안에 넣어놓을 것인가에 대해서도 중간에 변동이 있었습니다. 고민끝에 저는 이러한 구조로 데이터를 작성했습니다.
함수 구성
home은 크게 6가지 함수로 동작합니다.
checkDone()
: 할일 클릭을 감지하고 처리함todoCount()
: 미완료 할일의 수를 화면에 표시함 (완료 버튼 클릭, 새항목 추가 등 미완료 할일의 수가 변경되는 지점마다 호출됨)listToTodo(list)
: list를 탐색하면서 요소를 하나씩 Todo로 만들어서 화면에 그림listToTodoList(list, categoryName)
:listToTodo()
에서 호출되는 함수로, 상수 데이터에서 두번째 depth에 있는 할일 목록(list)를 다룸checkModal()
: modal의 열고 닫힘을 관리하는 함수resolveModal()
: modal안에서 일어나는 폼 제출(할일 추가)를 관리하는 함수mycategory는 크게 6가지 함수로 동작합니다.
makeCategories(list)
: list(카테고리 목록 리스트)를 탐색하면서 하나씩 카테고리 박스로 만들어서 화면에 그림extractCategoryName(list)
: list(전체 할일 목록 데이터)를 탐색하면서 카테고리 이름만을 골라내어 새로운 리스트로 만들어 반환함resolveDragDrop(item, parent)
: 드래그앤드롭 기능을 처리함arrayInsertAfter(array, target, reference)
: array에서 target value를 reference value의 바로 뒤로 순서를 옮기는 함수 -resolveDragDrop()
에서 사용arrayInsertBefore(array, target, reference)
: array에서 target value를 reference value의 바로 앞으로 순서를 옮기는 함수 -resolveDragDrop()
에서 사용changeLocalStorage(list)
: 변경된 categoryList(순서)에 따라 전체 데이터를 재배치하여 localStorage에 반영하는 함수새로고침 없이 작동하도록 하기
과제 시뮬 영상 보니까 모든 기능 작동이 새로고침 없이 진행되길래 저도 할일추가 할 때 preventDefault로 새로고침을 방지하고 새로고침이 없어도 바로바로 반영이 되도록 구현했습니다! 그게 진짜진짜 어렵더라구요 8ㅅ8
🥺 소요 시간, 어려웠던 점
15h+ ??? ㅠㅠ
할일 추가 모달 로직
처음에 모달의 열고 닫힘을 감지하고 어떤 카테고리를 클릭해서 열린건지를 알아내서 할일을 추가하는 것 까지를 하나의 함수에서 모두 처리했었는데요! 이렇게 하니까 한번 모달이 작동되고나서 또 계속해서 작동이 되려면 (즉, 할일추가 + 버튼이 눌림을addEventListner
로 감지하려면) 또다시 이 함수를 호출해야 했어요. 그런데 그렇게 하니까 recursion이 일어나서 아주 엉망이 된거예요... 진짜 이거 고치는데만 반나절 쓴 것 같아요. 해결 방법은 바로 '모달의 열고 닫힘을 관리하는 함수'와 '모달 안에서 일어나는 일을 관리하는 함수'를 분리하는 것이었습니다. 즉, 전자의 함수는 진짜 모달의 '열고 닫힘'에만 관여하는 거죠. 이게 말로 설명하려니 어려운데... 아무튼 함수를 기능별로 분류하는 것이 얼마나 중요한 일인지 알았습니다. 은빈이가 자스 클린 코드 관련 레포를 스타했길래 저도 읽어보니깐 (굉장히 유용한 아티클이더라구요!) 함수를 기능단위로 쪼개는게 중요하고, 또 그래야 함수 이름도 명확해지더라구요. 이번 기회로 확실히 배웠습니다.Drag&Drop
처음 해보는 기능이라 약간 막막했는데, 이 자료를 한번 따라하고 나서 진행하니 훨씬 수월했던 것 같아요! 근데 어려웠던 건, 이 드래그한 카테고리(draggedItem
)를 드롭한 부분(dropZone
)의 앞으로 이동하게 할 건지, 뒤로 이동하게 할 건지를 제가 짜야하는 부분이었어요. 그니까 원래draggedItem
이dropZone
보다 앞에 있던 거면dropZone
의 뒤에 붙여줘야 하고, 뒤에 있던 거면dropZone
의 앞에 붙여줘야 했어요. 이 사실을 깨닫고 일단 카테고리 목록을 순서대로 저장하는 list를 하나 만들고, 이동이 일어날 때마다draggedItem
에 해당하는 카테고리와dropZone
에 해당하는 카테고리의 인덱스를 확인해서arrayInsertBefore(array, target, reference)
또는arrayInsertAfter(array, target, reference)
둘 중 하나를 호출했습니다.PR 관련...
코드가 길어지니까 PR 남기기도 난감하네요... 다음 과제부터는 그냥 코드에 주석으로 설명을 남기면 좋을 것 같습니다!🌈 구현 결과물
미완료한 할일 수 반영
default.mov
항목 추가
default.mov
카테고리 순서 변경
default.mov