2차 공부/TIL

24.07.16 미니프로젝트 troubleshooting

공대탈출 2024. 7. 16. 22:06

미니프로젝트 와이어프레임

한 페이지에서 조를 소개하는 화면이 먼저 보인다. 소개하는 부분의 바로 아래에는 아래를 향하는 화살표가 존재하며

직접 스크롤을 내려도 간단한 멤버소개카드가 모여있는 곳으로 이동 가능하며, 화살표를 클릭해도 해당 부분으로 화면을 이동시킨다.

 

멤버 소개 데이터는 Firebase에 직접 데이터를 미리 집어넣었다.

이전에는 데이터 형태가 같은 임시데이터를 변수에 담아 사용했는데, 세팅때부터 firebase를 세팅하여 해당 데이터로 연습하며 페이지를 만드는게 두번 일을 하지 않고 더 나을 것이라는 충고를 듣고 변경했다.

 

또한 각각의 멤버 카드에는 각 멤버들의 이름, 소개, 댓글목록이 간략히 보이며 소개 혹은 댓글목록을 클릭하면 상세한 내용이 나오는 모달창이 등장한다.

 

모달창 배경은 흐리게 처리가 되어있으며 배경은 클릭이 불가하다. 또한 사용자의 화면 중앙에 고정되어 따라다닌다.

모달 내부에는 닫기버튼이 제일 먼저 존재한다. 닫기버튼으로만 모달을 없앨 수 있다.

위에는 멤버가 등록한 사진과 함께 이름과 생략되지 않은 설명이 존재한다.

바로 아래에 다른 사람들이 해당 인원에게 달은 댓글목록이 출력된다.

 

먼저 사용한 방법

<script type="module">
	const memberArray = firebase에서 가져온 데이터
</script>
<button class="btnOpenModal">1번 멤버</button>
<button class="btnOpenModal">2번 멤버</button>

<div class="modal">
	<button class="closeModalBtn">X</button>
	<div class="memberDescription"></div>
</div>

<script>
	const openModal = document.querySelector('.btnOpenModal')
    const parent = document.querySelector('.memberDescription')
    const closeBtn = document.querySelector('.closeModalBtn')
    openModal.addEventListener("click", function () {
    	openModal.style.display = "flex"
        memberArray.forEach((el) => {
        	추가하는 명령
        })
    })
</script>

jQuery를 사용하지 않고 바닐라 js로 먼저 구현해보고자 하였다. eventListener에 대한 이해가 적었기 때문에 이러한 선택을 하였다.

원하는대로 작동하지 않았다.

1번 멤버 버튼을 눌렀을 때에는 모달이 켜지고 데이터가 원하는대로 잘 들어갔지만, 2번버튼은 작동하지 않았다.

 

그 이유는 querySelector에 있었다.

querySelector은 문서 내 일치하는 첫번째 Element만 반환하기 때문이었다. 그래서 다른 버튼에는 event가 연결되지 않았던 것이다.

 

두번째로 작성한 코드

<script type="module">
	const memberArray = firebase에서 가져온 데이터
</script>
<button class="btnOpenModal1" onclick="open(btnOpenModal1)">1번 멤버</button>
<button class="btnOpenModal2" onclick="open(btnOpenModal1)">2번 멤버</button>

<div class="modal">
	<button class="closeModalBtn">X</button>
	<div class="memberDescription"></div>
</div>

<script>
	const openModal = document.querySelector('.btnOpenModal')
    const parent = document.querySelector('.memberDescription')
    const closeBtn = document.querySelector('.closeModalBtn')
    function open(query) {
        ${query}.addEventListener("click", function () {
            openModal.style.display = "flex"
            memberArray.forEach((el) => {
                추가하는 명령
            })
        })
    }
</script>

첫번째 시도에서 문제라고 생각했던 부분이 모든 태그에 지정되지 않는것이라고 생각하여 함수형태로 eventListener를 만들고 onClick으로 각 버튼에 적용시켰다. 정확하진 않지만 대략 저러한 코드였다.

 

하지만 다른 문제가 발생하였다. 원하는 데이터가 잘 들어가긴했지만, 각각의 버튼을 두번 눌러야만 모달이 나왔다.

또한, 모달을 닫고 다시 여는 과정에서 같은 데이터가 밑에 추가되어 모달을 벗어나게 보였다.

 

문제원인을 파악하기 힘들어 튜터님께 질문을 했다.

이러이러한 기능을 구현해야하고, 어떤 작업을 했었으며 어떤 문제점이 있어 함수에 집어넣었고, onclick으로 적용시키자 이러한 문제가 생겼다라고 전달했다.

 

튜터님은 addEventListener이 event를 태그에 부착하는 목적이라고 설명해주셨다.

함수가 실행되면 특정 태그에 event가 달리는 모양인데, 그래서 모달을 킬 때마다 데이터가 중첩된다는 뜻이었다. 그리고 한번 눌러야만 이벤트가 달리기 때문에 모달을 키려면 더블클릭해야했던 것도 풀리게 되었다.

 

따라서 함수형태로 eventListener을 달면 의도와 다르게 작동할 수 있다는 것을 알게되었으며, querySelectorAll이라는 메서드를 알게되었다.

querySelectorAll은 querySelector와 다르게 해당 class를 가진 모든 태그를 선택해주는 것이었다.

 

따라서 해당 메서드를 사용하여 코드를 수정했다.

<script type="module">
	const memberArray = firebase에서 가져온 데이터
</script>
<button class="btnOpenModal">1번 멤버</button>
<button class="btnOpenModal">2번 멤버</button>

<div class="modal">
	<button class="closeModalBtn">X</button>
	<div class="memberDescription"></div>
</div>

<script>
	const openModal = document.querySelectorAll('.btnOpenModal')
    const parent = document.querySelector('.memberDescription')
    const closeBtn = document.querySelector('.closeModalBtn')
    openModal.forEach(function(member) {
        openModal.addEventListener("click", function () {
            openModal.style.display = "flex"
            memberArray.forEach((el) => {
                추가하는 명령
            })
        })
    })
</script>

대충 이러한 형태로 모든 btnOpenModal을 가진 openModal을 forEach를 사용하여 eventListener을 달아주었으며, 잘 작동하였다.

아까 문제점으로 보였던 더블클릭이슈나 데이터가 계속해서 쌓이는 문제도 해당 방식으로 완전히 제거가 되었다.


다음으로 팀에서 사용하기로한 jquery를 이용하고자 모든 click event를 jquery화 시켰다.

<html>
	<head>
    	<script type="module>
            //firebase생략
            let docs = await getDocs(collection(db, "members"));
            let memberArray = [];
            docs.forEach((doc) => {
                memberArray.push(doc.data());
            });

            // 모달관련 스크립트
            const modal = $(".modal");
            let parent = $(".memberDesc");
            $(".btnOpenModal").click(function (e) {
                modal.css("display", "flex");
                const targetMemberId = this.id;
                const { name, img, desc, comment } = memberArray[targetMemberId - 1];
                let commentBox = ``;
                comment.forEach(
                  (el) =>
                    (commentBox += `<p><span>${el.cName}</span> : <span>${el.cDesc}</span></p>`)
                );
                let temp_html = `
                          <div class="memberIntroduce">
                              <image
                                  class="memberImage"
                                  src=${img}
                                  alt="멤버 이미지"
                              />
                              <div>
                                  <p><span>이름</span> : <span>${name}</span></p>
                                  <p>
                                      <span>간단한 소개</span> :
                                      <span
                                          >${desc}</span
                                      >
                                  </p>
                              </div>
                          </div>
                          <div class="memberCommentBox">
                          ${commentBox}
                          </div>`;
                parent.append(temp_html);
            });
            const btnCloseModal = $(".btnCloseModal");
            btnCloseModal.click(function () {
                modal.css("display", "none");
                parent.empty();
            });
        </script>
    </head>
    
    <body>
        <button class="btnOpenModal" id="1">1 모달 테스트</button>
        <button class="btnOpenModal" id="2">2 모달 테스트</button>
        <button class="btnOpenModal" id="3">3 모달 테스트</button>
        <button class="btnOpenModal" id="4">4 모달 테스트</button>
        <button class="btnOpenModal" id="5">5 모달 테스트</button>
        
        <div class="modal">
            <div class="memberModal">
                <div class="closeBtnWrap">
                    <button class="btnCloseModal"></button>
                </div>
                <div class="memberDesc"></div>
            </div>
        </div>
        
    </body>
    
</html>

기존 document.querySelector이나 querySelectorAll으로 잡던 class는 $(.'abc')형태로 잡아주었고, display값을 바꾸는 것도 jquery에 맞추어 .css('display', 'flex') 이러한 형태로 바꿨다.

 

기존 바닐라 자바스크립트에선 querySelectorAll으로 잡은 모든 태그들을 forEach를 사용하여 각각 eventListener을 달아주었는데, jquery로 잡은 특정 태그들은 그냥 .click()이벤트를 달아주니 모두 각각의 데이터를 가져오는 것으로 잘 적용이 되었다.


튜터님께 질문할 때에는 확실히 어떤 문제가있는지, 그 문제를 어떻게 해결하려고했는지, 어떤 문제가 발생했는지에대해 잘 설명해드리면 답변도 확실하게 빠르게 돌아온다.

또한 그런 상황과 문제들을 미리 잘 적어두어야 TIL에도 상세히 적을 수 있어 나중에 같은 문제가 발생했을 때를 대비할 수 있는 것같다.

앞으로는 TIL을 미리 만들어두어 임시저장으로 상황과 코드를 정리해두어야겠다고 생각하였다.