슬라이더 구현

황준승·2022년 4월 15일
0
post-thumbnail

목차

  1. 코드
  2. 코드 구현 설명

1. 코드

2. 코드 구현 설명

CSS

active, prev, next 속성 부여

슬라이더를 구현하기 위해서는 다섯가지 슬라이더 블록을 한 곳에 모두 겹치게 하여 .active, .prev, .next에 각각 css 스타일링을 부여하여 구현할 수 있다.

.active : 겹쳐지는 다섯가지 슬라이드 중 유일하게 보여지는 블록이다. 따라서 안 보여지는 4가지 블록의 투명도 속성(opacity)를 0으로 두고 .active 속성을 가진 블록만 투명도 속성(.opacity)를 1로 두어 구현할 수 있다. 추가적으로 z-index와 opacity에도 transform액션을 주어서 좀 더 동적인 UI를 구성하였습니다.

.prev : .active 속성 이전의 블록을 나타냅니다. 넘겨주는 css 전환을 주기 위해 다음과 같은 속성을 주었습니다.

transform : translateX(100%); // prev
  • 설명 : next버튼을 눌렀을 때 현재 화면이 prev가 됨으로 이때 translateX(100%) 를 주어 오른쪽으로 넘기는 애니메이션을 주었습니다.

.next : .active 속성의 다음 블록을 나타냅니다. 넘겨주는 css 전환을 주기 위해 다음과 같은 속성을 주었습니다.

transform : translateX(-100%)' // next
  • 설명 : 마찬가지로 prev버튼을 눌렀을 때 현재 화면이 next가 됨으로 이때 translateX(-100%)를 주어 왼쪽으로 넘기는 애니메이션을 주었습니다.

슬라이더 겹치게 하기

평소 div를 나란히 작성하게 되면 세로 일렬로 줄세우기를 하게 된다. 왜냐하면 position : relative가 기본값이기 때문

따라서 각 겹치게 하기 위한 슬라이더 블록

<div class = "carousel_item"></div>

들의 속성을 position = absolute로 설정해주면 이를 해결 할 수 있다.


가운데 정렬

제가 평소에 많이 쓰는 가운데 정렬의 경우 다음과 같다.

display : flex;
justify-content : center;
align-items : center 

상위 태그를 다음과 같이 작성하고 하위 태그에 position :absolute를 할 경우 content가 가운데 정확히 놓여지지 않고 블록이 가운데 지점부터 시작하는 것을 알 수 있다.

이를 해결하기 위해
가로 정렬을 다음과 같이 하였다.

width : 90%;
min-height: 100vh;
margin : auto;

그리고 세로 정렬을 내가 넣고자하는 div의 height값을 구하여 이를 전체 세로 길이의 절반(50vh)에서 빼주어 위치를 조정하였습니다.

position: relative; // 하위 태그의 position :absolute 설정을 위해
top: calc(50vh - 100px);

JS

active, prev, next className 부여 방법

버튼을 누를 때마다 currentId값이 상승, 하강함에 따라 이에 따른 prev, current, next값의 인덱스를 계산하여 각각의 속성을 부여하는 방식으로 구현하였습니다.

  // active, next, prev 할당 함수
  this.assignActiveNextPrev = () => {
    const { currentId, carouselListLength } = this;

    const current =
      currentId < 0
        ? (carouselListLength + (currentId % 5)) % 5
        : currentId % 5;

    const prev = current === 0 ? carouselListLength - 1 : (current - 1) % 5;
    const next = current === carouselListLength ? 0 : (current + 1) % 5;

    return { newPrev: prev, newCurrent: current, newNext: next };
  };

추가적으로 각각의 클래스에게 부여하고 다음 이벤트가 들어왔을 시 이를 리셋하고 새로 구한 prev, current, next 값에 따라 그에 맞는 태그에 클래스 속성을 부여해야 합니다.

첫번째 방법
모든 태그 리스트를 반복문을 돌리면서 각각의 클래스명을 부여하는 방식


    carouselItemList.forEach((carouselItem, idx) => {
      switch (idx) {
        case prev:
          carouselItem.className = carouselItemClassName + " prev";
          break;
        case current:
          carouselItem.className = carouselItemClassName + " active";
          break;
        case next:
          carouselItem.className = carouselItemClassName + " next";
          break;
        default:
          carouselItem.className = carouselItemClassName;
      }
    });

다음과 같이 코드를 짤 경우 엄청나게 많은 슬라이더 양이 있을 경우 이에 따른 성능 저하가 고려되어졌습니다.

따라서 저는 두번째 방법을 생각해 보았습니다.

두번째 방법
버튼 이벤트 동작 시 이전 인덱스 (prev, current, next)를 제거하고 새로 구한 인덱스(newPrev, newCurrent, newNext)를 구하고 이를 추가하는 식으로 구현하였습니다.

  // active, next, prev 설정하여 보여줄 Carousel화면 결정
  this.showCarouselItem = () => {
    const { prev, current, next } = this;

    // active 설정이 있을 경우
    if (![prev, current, next].includes(null)) {
      // active 설정 삭제
      this.addOrRemoveActiveClassName({ prev, current, next }, removeClassName);
    }

    // active 설정을 위한 index 계산
    const { newPrev, newCurrent, newNext } = this.assignActiveNextPrev();

    // active 설정 추가
    this.addOrRemoveActiveClassName(
      { prev: newPrev, current: newCurrent, next: newNext },
      addClassName
    );

    this.prev = newPrev;
    this.current = newCurrent;
    this.next = newNext;
  };

고려사항

  • react 스러운 개발 방식을 위해 SPA 어플리케이션 방식으로 구현
  • 함수는 하나의 기능만을 수행하고 독립적으로 작성하도록 구현하였습니다.

수정해야할 사항

  1. 첫번째 방법 리터럴 적용하기
          carouselItem.className = carouselItemClassName + " prev";
          break;
        case current:
          carouselItem.className = carouselItemClassName + " active";
          break;
        case next:
          carouselItem.className = carouselItemClassName + " next";

위와 같은 구문을 리터럴을 사용하여 적용시키자

  1. index 로직할당 구현 변경
    더러운 코드를 갈아 엎자

  2. 슬라이드 클릭 시 애니메이션 변경

  • 사용자 경험에 위해 이를 반대로 하는 것이 좋다.

오른쪽 클릭 시 -100%
왼쪽 클릭 시 +100%

profile
다른 사람들이 이해하기 쉽게 기록하고 공유하자!!

0개의 댓글