Flex Panel Gallery

DAY 5-Flex Panel Gallery

CODE

기본 구현 사항: 카드를 클릭할 시 카드의 크기가 확대되며 상하단부에서 숨겨져 있던 문구가 나오도록 함

1) 세로로 쌓여 있는 .panels div에 display: flex 속성 할당하여

다음과 같이 가로로 배치되도록 함

2) 각각의 카드 하나하나에 모두 들어간 .panel class에 아래와 같이 속성 추가

flex: 1;
justify-content: center;
display: flex;
flex-direction: column;

  • flex-item들이 빈 공간을 채우게 하면서 동시에 flex-item들 또한 flex-container가 되도록 함 -> 내부의 요소들을 세로로 중앙 정렬하며 열방향으로 배치

3) .panel 클래스 내의 모든 요소에 대하여 다음 속성 추가

flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: center;

  • 카드 내의 문구들(

    )이 남아있는 빈 공간을 서로 동일하게 분배받으며 채우고, 그 공간 내에서 가로/세로 방향 모두 중앙정렬

4) 카드 내의 첫번째 문구와 마지막 문구를 기본 상태(닫힌 상태)일 때는 사라져있도록, 클릭된 상태(열린 상태)일 때는 나타나도록 속성 추가

.panel > *:first-child {
        transform: translateY(-100%);
}
.panel.open-active > *:first-child {
        transform: translateY(0);
}
.panel > *:last-child {
        transform: translateY(100%);
}
.panel.open-active > *:last-child {
        transform: translateY(0);
}

  • .panel class의 첫번째, 마지막 자식 요소는 Y축 방향으로 각각 -100%, 100%으로 이동시키고, 만약 .open-active class가 추가된다면 각각 0, 0으로 이동하도록 함

5) .panel.open class에 flex: 5; 속성 할당 -> open된 상태일 때 카드의 크기가 커질 수 있도록

6) javascript 작업 시작 - .panel class 모두를 변수 panels에 할당

const panels = document.querySelectorAll(".panel");

7) toggle() 함수 선언 -> click 이벤트가 발생하면 실행되도록 함

function toggle() {}

panels.forEach((panel) => {        panel.addEventListener("click", toggle);

8) 클릭한 이벤트가 발동된 요소에 open 클래스를 토클링하도록 함

function toggle() {
        this.classList.toggle("open");
}

9) toggleActive() 함수 선언 -> transitionend 이벤트가 발생하면 실행되도록 함

function toggleActive(e) {}

panels.forEach((panel) =>
panel.addEventListener("transitionend", toggleActive)
);

10) transition이 끝났을 때, 해당 이벤트의 propertyName이 "flex"라는 단어를 포함한다면, 즉, .panel class에 .open class가 추가되면서 카드의 크기가 커진다면(flex: 5;) classList에 "open-active"를 토글링 하도록 함

function toggleActive(e) {
        if (e.propertyName.includes("flex")) {
          this.classList.toggle("open-active");
        }
}

내가 추가한 기능: 카드 클릭 시 이전에 클릭되었던 카드들을 자동으로 닫기

1) closeAllPanels() 함수 선언 -> panels에 forEach 메소드 사용하여 panel 하나하나를 순회하며 classList에서 "open" class를 제거

function closeAllPanels() {
        panels.forEach((panel) => {
          panel.classList.remove("open");
        });
}

2) toggle() 함수에 closeAllPanels() 함수를 추가 -> 만약 classList에 "open-active" class가 포함되어 있다면 그대로 return하여 toggle() 함수 종료하여 "open" class가 더해지지 않도록 함

function toggle() {
        closeAllPanels();
        if (this.classList.contains("open-active")) {
          return;
        }
        this.classList.toggle("open");
}
  • 만약 조건문을 추가하지 않으면 클릭해서 open된 카드를 재클릭해서 닫으려고 하면 click event 발생 -> toggle() 실행 -> closeAllPanels() 실행 -> panels 하나하나 순회하며 classList에서 open class 삭제 -> toggle()의 this.classList.toggle("open")이 실행되며 삭제된 open class가 다시 토클링(추가)되므로 카드를 닫을 수 없음 -> 따라서 해당 시점에서 open-active class가 포함되어 있는 요소, 즉, 이전에 클릭해서 열린 (closeAllPanels() 함수에 의해 open class가 삭제되었지만 아직 open-active class는 제거 되지 않은)요소에는 open class를 토글링(추가)하지 않도록 하는 것

  • open-active class는 open class가 remove되면서 발생하는 transition이 끝날 때 발동되는 toggleActive() 함수에 의해 수거됨

What I Learned

이번엔 특별히 어떤 기술적인 면을 배웠다기 보다는 함수에 의해 어떤 작업이 이루어지는지, 그 작업은 정확히 언제 일어나는지 등을 정확하게 파악하는 것이 중요하다는 것을 깨달았다. 추가기능을 구현할 때 transitionend event가 발생하는 시점이 헷갈리기도 했었고 closeAllPanels()에 의해 open class를 제거했지만 toggle()에 의해 다시 추가되는 등 원치 않는 사건(?)들이 발생하면서 조금 헤맸었기 때문이다.

그래도 차근차근 A가 발발하며 B가 일어나고, B로 인해 C가 일어나는 순서를 천천히 파악하기 위해 노력했고, 그 덕분에 원하는 대로 작동하는 코드를 짤 수 있었다.

조금씩 이 챌린지에 정이 붙기 시작하는 것 같다. 완주까지 열심히 연구해야겠다.

좋은 웹페이지 즐겨찾기