나만의 아고라스테이츠 만들기 미니 프로젝트
코드스테이츠 부트캠프 section1을 마무리하며 작은 솔로 프로젝트를 진행했다.
'아고라스테이츠'는 코드스테이츠 수강생들을 위한 일종의 질문 게시판인데
이것을 나만의 스타일로 다시 구성해보는 것이 과제였다.
아주 기본적인 틀과 힌트만 주어지고 나머지는 전부 스스로 알아내고 만들어 내야 해서
지금까지의 과제와는 달리 난이도가 있었지만 도전의식에 불타서 advanced 과제까지 잘 달성했다!
그 과정에서 배운 것이 아주아주 많았기에 잊기 전에 잘 정리해둬야겠다고 생각했다.
1. Bare minimum 과제 목표
• 디스커션 나열 기능
• CSS로 꾸미기
• 디스커션 추가
• Github page 배포
📌 디스커션 나열 기능
게시물 정보가 들어 있는 객체가 담긴 배열로부터 데이터를 불러와서 화면에 렌더한다.
4단계의 과정을 거쳐 화면에 요소들을 띄울 수 있다.
• 내용을 담을 html 요소를 만든다.
• 만든 요소에 객체에서 불러온 값을 넣는다.
• 클래스를 붙인다.
• 적절한 위치에 append 한다.
const avatarImg = document.createElement("img"); //img 요소 만들고 변수에 할당
avatarImg.src = obj.avatarUrl; //객체에서 값을 불러와 attribute로 할당
avatarImg.className = "discussion__avatar--image"; //클래스 붙이기
avatarWrapper.append(avatarImg); //이미지 칸에 append
위 예시는 아바타 이미지를 만드는 방법이다.
결국 화면에 렌더한다는 것은 작은 요소들부터 큰 요소에 이르기까지 이 작업을 반복하는 과정이다.
요소 만들고 -> 내용 넣고 -> 클래스 붙이고 -> append의 무한 반복!
📌 CSS로 꾸미기
제목과 질문 폼, 질문 리스트를 화면에 보기 좋게 배치한다.
나는 동물의 숲 테마를 선택해 레퍼런스를 참고하고 제목과 질문 폼을 테마에 맞춰 만드는 것에 집중했다.
일단 테마와 레퍼런스만 잘 선택해도 디자인하기가 훨씬 수월한 것 같다.
평소에 광고나 웹페이지에서 예쁜 디자인이 있으면 잘 스크랩해둬야겠다.
📌 디스커션 추가
폼을 작성하고 제출하면 데이터를 받아서 질문 리스트에 추가한다.
이 부분에서는 submit 이벤트를 감지해서 이벤트 객체에 접근해야 한다.
• 이벤트 객체의 해당 input 요소에 value로 들어있는 값을 새로운 객체에 넣는다.
• 새로운 객체를 원본 데이터 배열에 unshift(맨 앞에 삽입) 한다.
• 기존 화면에 표시돼 있던 html 요소들을 비우고 화면에 새로 렌더한다.
• input value에 빈 문자열을 넣어 내용이 지워지도록 설정한다.
📌 Github page 배포
깃허브 페이지 배포는 이전에도 해 봐서 그리 어렵지 않았다.
페이지 배포를 하면 다른 사람이 링크를 통해 내 작업물을 손쉽게 볼 수 있다!
2. Advanced challenge와 추가로 구현한 것
• 현지 시각 적용
• 페이지네이션
• 로컬 스토리지
• 제목 애니메이션
• 유저 아바타 랜덤 부여
📌 현지 시각 적용
제공된 더미 데이터에는 등록 시각이 ISO 표준에 따라 표기돼 있었고, 기준 시각도 영국에 맞춰져 있었다.
따라서 시각 표기법을 수정하고 시간도 한국에 맞게 바꿔야 했다.
이것은 원래의 시각에서 slice로 필요한 부분만 잘라 와 9시간을 더하고
12시를 기준으로 오전 오후를 표기해 주는 간단한 함수로 해결했다.
📌 페이지네이션
제공된 데이터가 40개가 넘었고, 추가로 질문을 등록할 수도 있기 때문에 목록이 상당히 길었다.
페이지네이션을 활용하면 화면에 원하는 만큼만 목록을 표기할 수 있어 한눈에 보기가 편해진다.
페이지네이션 구현 과정은 다음과 같다.
• 한 페이지에 들어갈 목록의 수를 정한다.
• 목록의 총 개수를 페이지 당 목록 수로 나눠 페이지 수를 결정한다.
• 페이지 숫자를 화면에 표시한다.
• 클릭 이벤트가 발생하면 현재 페이지가 어디인지 알 수 있도록 숫자 요소를 스타일링한다.
• 동시에 총 목록에서 현재 페이지에 해당하는 만큼의 목록을 화면에 표시한다.
이 중 핵심이자 가장 까다로운 과정은 5번, 즉 화면에 현재 페이지 만큼의 목록을 표시하는 부분이다.
내가 선택한 방법은 일단 모든 페이지에 hide 클래스를 부여해 전체 목록을 화면에서 감추고(display: none)
잘라낸 페이지 만큼만 다시 hide 클래스를 없애서 화면에 표시하는 방법이었다.
⚠️ 여기서 돌아볼 점!
일단은 페이지네이션이 작동하도록 하는 것에 목적이 있었기 때문에 이런 식으로 구현을 했는데,
프로젝트를 완료하고 나서 다른 동기들의 코드를 살펴보며 곰곰히 생각하니 내 방식에는 큰 약점이 있었다.
지금은 질문 목록의 수가 고작해야 수십 개 정도로 적지만,
진짜로 게시판을 운영하게 된다면 수백 개를 넘어 어쩌면 수천 수만 개의 게시물이 올라오게 될 것이다.
이 경우에는 모든 게시물을 전부 렌더하고 hide 클래스를 부여한다면 사이트를 로드하는 데 엄청난 시간이 걸리게 된다.
따라서 애초에 렌더하는 방식을 바꿔 해당 페이지 목록만 화면에 렌더하는 것이 올바른 페이지네이션 구현법일 것이다.
코드를 직접 고치지는 못했기 때문에 올바른 페이지네이션 구현법을 의사코드로만 작성해 보았다.
// 페이지네이션 함수
// listPerPage = 한 페이지에 들어갈 목록의 수
// DataLength = 전체 데이터의 목록 수
// pageCount = DataLength/ListPerPage 화면에 표시할 페이지 숫자의 개수
// pageCount만큼의 html 요소를 만들어 필요한 곳에 append
// 클릭 이벤트를 감지해 currnetPage에 클릭한 페이지 번호를 할당
// 렌더 함수 실행
// 렌더 함수(append할 부모 요소, currentPage)
// currentPage 전달인자를 기반으로 화면에 표시할 데이터의 시작 인덱스와 끝 인덱스를 계산
// start = currentPage * listPerPage
// end = start + listPerPage
// 인덱스를 따라가며 데이터에 html 요소를 붙여주는 반복문 실행
// append할 부모 요소에 append
+) 추가
결국 기존 코드에서 페이지네이션 일부 기능이 제대로 돌아가지 않는 걸 알게 돼서 전부 코드를 뜯어 고쳤다.
그냥 의사코드만 작성했을 때와 달리 실제로 구현해 보니 여러 가지 문제에 부딪혔고
수많은 '삽질' 끝에 또다른 새로운 것들을 배울 수 있었다.
가장 나를 골치아프게 한 것은 렌더와 동시에 화면에 숫자를 표시할 때
숫자 칸의 자식 요소들을 전부 비우고 새로 숫자를 계산해서 표시하는데
이 과정에서 숫자에 붙여 놨던 이벤트 리스너가 싹 사라져 버린다는 것이었다..
이걸 고치느라 별별 수단을 다 써보다가 결국 숫자 표시 함수에 이벤트 리스너를 다 넣어놓았는데,
구글링을 해 보니 '이벤트 버블링' 때문에 굳이 그렇게 하지 않아도 된다는 것을 알게 되었다.
이걸 진작에 알았다면 그 수많은 삽질을 하지 않아도 되었을 텐데...
어쨌든 알게 되었으니 다시는 같은 고생을 하지 않을 수 있게 되었다!
숫자 a 태그의 부모 요소에 이벤트리스너를 붙여 놓고 숫자를 클릭했을 때 target 값을 받아오게 해서 해결!
📌 로컬 스토리지
로컬 스토리지 구현법은 처음에는 엄두가 안 났지만 막상 알고 보니 그렇게 어려운 기능은 아니었다.
기존에 주어진 데이터 대신에 로컬스토리지 공간에 데이터를 전부 저장하고
데이터를 로드하고 추가하는 소스를 로컬스토리지로 바꾸면 된다.
다만 주의할 것은 로컬스토리지 공간에는 오로지 문자열의 형태로만 값을 저장할 수 있기 때문에
JSON.stringify()와 JSON.parse()를 통해서 배열과 문자열 사이의 변환을 해 줘야 한다는 점이다.
나는 아래 링크에서 도움을 받아 로컬 스토리지 구현 방법을 구상할 수 있었다.
https://stackoverflow.com/questions/3357553/how-do-i-store-an-array-in-localstorage
📌 제목 애니메이션
CSS 수업 동안에 동기들 과제에서 애니메이션을 배워 이번에 적용해 보았다.
생각보다 간편하게 구현할 수 있어서 앞으로 종종 써먹을 것 같다.
📌 유저 아바타 랜덤 부여
유저 사진 10개를 만들어 1~10 사이의 수를 랜덤 생성하고 유저 아바타를 랜덤 부여했다.
더불어 이미 제공된 더미 데이터의 사진도 처음에 전부 바꾸도록 설정해 두었다.
덕분에 동물의숲 컨셉을 좀 더 일관성 있게 구성할 수 있었다!
3. 그밖의 돌아볼 점들
• TDZ 문제
• 여전히 어려운 CSS
📌 TDZ 문제
여러 기능들을 하나씩 더하면서 구현하다 보니 기존에 써놨던 코드들을 고치고
순서를 바꾸거나 새로운 변수 및 함수를 선언하는 일이 잦았는데,
그러다 보니 TDZ를 경험하게 되었다.
TDZ에 관해서 알게 되었을 때는 그런 경험을 할 일이 있을까 싶었는데
실제로 경험하고 보니 이런 문제에 부딪히는 일이 종종 있을 수 있겠다고 느꼈다.
앞으로는 기능 구현 시에 선언의 위치에 좀 더 신경을 써서 오류가 나지 않도록 해야겠다.
📌 CSS
CSS는 욕심 내서 건드리기 시작하면 한도 끝도 없는 것 같다...
이번에 새로 익히게 된 것 몇 가지를 적어두려 한다.
• vw, vh로 값을 설정할 때는 min-width, min-height를 같이 설정해야 한다.
그렇지 않으면 화면을 줄였을 때 다른 요소에 잡아먹히게 된다.
• font-face
그동안은 구글 폰트로만 폰트를 지정했었는데
이번에는 소스폴더에 폰트를 넣어 두고 받아서 띄울 수 있게 했다.
이때 지정해야 하는 것이 font-face.
font-family와 url을 명시해 두면 사용할 수 있다.
• word-wrap: word-break
지정된 영역을 넘어가지 않도록 줄바꿈
• transform:rotate(deg)
지정한 각도만큼 요소를 회전시킬 수 있다.
4. 다른 아이디어들
• 탑 버튼: 누르면 맨 위로 이동
• 모달창: 질문 폼을 숨겨 두고 클릭했을 때 모달창으로 보이게
• 스크롤: 질문 리스트를 보여주는 div를 작게 만들고 스크롤로 볼 수 있게
• 스트롤하면 따라오는 질문 폼: 왼쪽에 질문 폼을 따로 두고 리스트를 스크롤할 때 따라오게
동기들의 완성작을 보면서 여러 좋은 아이디어들이 있어 기억해 뒀다 나중에 시도해 보면 좋겠다고 생각했다.
쉽지 않았지만 그만큼 재밌었고 많이 배울 수 있었던 미니 프로젝트!
다음 프로젝트를 할 때쯤이면 더 많이 발전해 있기를 바란다😃
'프로젝트 > 미니 프로젝트 & 과제' 카테고리의 다른 글
[과제] Mini node server (2) | 2023.04.04 |
---|---|
[과제] 반복문으로 map, filter, reduce 만들기 (2) | 2023.03.17 |
[과제] 유효성 검사 (0) | 2023.03.08 |
[과제] Koans (0) | 2023.03.03 |
[과제] 계산기 기능 구현하기 (0) | 2023.02.23 |