carousel 만들기

박재성·2022년 4월 28일
0
post-thumbnail
post-custom-banner

프로젝트를 진행하면서 캐러셀을 만들 일이 생겼다. 수 많은 리액트 라이브러리가 있지만, 공부를 하고 한 번도 만들어 본적 없는 것을 라이브러리로 만드는게 내키지 않았다.

그래서 순수하게 나만의 carousel을 만들기로 했다.

기본 구조

사실 캐러셀은 기본 구조만 알면 만드는 일은 어렵지 않다. 캐러셀을 구성하는 수 많은 방법 중에 나는 가장 기본적인 방법을 적용했다.

이것만 알면 된다.

  1. 이미지를 수평 배열한다.
  2. 슬라이드 아이템을 넣는 컨테이너의 크기를 아주 길게 잡는다.
  3. 가장 상단에 overflow: hidden을 준다.
  4. 아이템 크기만큼 transform: translate(-00px)를 적용한다.

4가지를 코드로 구현하면 정말 간단하게 나온다.

<OverFlow>
	<SlideContainer>
		{infiniteElements.map((e, index) => (
			<SlideInner key={index}>
				<SlideItem>
					<img src={e} alt="사진" />
				</SlideItem>
			</SlideInner>
		))}
	</SlideContainer>
</OverFlow>

스타일 코드는 더 간단한다.

import styled from "styled-components";

export const OverFlow = styled.div`
  overflow: hidden;
`;

export const SlideContainer = styled.div`
  width: ${(props) => props.width};
  transform: ${(props) => props.transform};
  transition: transform 0.5s;

`;
export const SlideInner = styled.div`
  width: 100vw;
  float: left;
`;
export const SlideItem = styled.div`
  width: 100%;
`;


끝이다. 이렇게 간단하게 캐러셀을 만들 수 있다. 하지만 이대로 끝내기 아쉬운 느낌이 들 것이다. 왜냐면 아이템의 마지막 요소에서 다음으로 넘어가면 아무것도 안 나오기 때문이다.!

그렇다면 무한 캐러셀을 만들어야하지 않겠나!

무한 캐러셀

무한 캐러셀은 기본 캐러셀보다 손 봐야 할 것이 많다. 일단 원리만 알면 어렵지 않게 구현이 가능하다!

기본 원리는 이것만 기억하자.

  1. 맨 뒤의 요소를 맨 앞에 복제해서 넣어주자.
  2. 맨 앞의 요소를 맨 뒤에 복제해서 넣어주자.
  3. 처음과 끝에 도달했을 때 서로 반대되는 곳으로 이동시킨다.

이 세 가지가 무한 캐러셀의 핵심이다. 하지만 문제는 transition 통해 요소가 밀리고 있는데 마지막에 도달했을 때, transition 효과를 제거해서 미리 요소의 위치를 옮겨놔야 한다.

styled-component의 Props를 이용해서 transition={LAST || FIRST ? `transform 0s` : `transform 0.5s`}을 적용시키면 마지막과 끝에서 transition을 적용하지 않고 요소를 바꾸게 된다.

일단 이렇게 하면 부드럽게 넘어가는 것이 구현이 안되지만 원하는 구현은 끝난다. 그렇다면 어떻게 마지막 디테일을 잡을 수 있을까?

리액트를 이용해서 state 변경을 통해 index를 props로 전달해서 확인하는데 이런 상황에서 요소를 바꿀 수 있는 방법은 더 고민을 해 봐야한다.

순수 자바스크립트였다면 돔 요소 조작을 통해 구현이 가능하지만 리액트는 그렇게 사용하면 안도이...

결론

무한 캐러셀이 약간 흠이 있게 구현이 되었지만 아주 간단하게 구현할 수 있어 라이브러리를 굳이 쓰지 않아도 되겠다는 생각이 들었다. 리액트를 잘하고 싶다...제발.

수정

무한 스크롤을 구현했다. 하지만 문제가 발생했다. 다른 곳은 모두 괜찮지만 딱 하나의 상황에서 사진이 늦게 나온다. 이건 왜 그러는지 전혀 이해가 가지 않는다.

일단 구현 방법은 기존의 방식과 다르지 않지만, transition과 index를 상태로 관리해서 스타일을 적용하도록 코드를 구성했다.


  const replaceSlide = (index) => {
    setTimeout(() => {
      setCurTransition("");
      setCurIndex(index);
    }, 500);
  };

  const handleSlide = (index) => {
    setCurIndex(index);
    if (index - 2 < 0) {
      index += ORIGINSIZE;
      replaceSlide(index);
    } else if (index - 2 >= ORIGINSIZE) {
      index -= ORIGINSIZE;
      replaceSlide(index);
    }
    setCurTransition(initTransition);
  };

replace함수는 마지막이나 처음 요소에 접근했을 때 상반되는 같은 요소에 바로 접근하기 위한 로직이다. 위에서 설명한 것으로 가장 앞 요소는 맨 뒤에 복제하고, 맨 뒤의 요소는 맨 앞에 복제한다.

이를 다이렉트로 순식간에 보내주기 위해 transition 효과를 없애고, 인덱스를 변경한다.

하지만 1에서 2로 넘어가는 상황에서 이미지가 느리게 로드 되고 있다. 다른 경우는 밀리는 것이 확실하게 확인할 수 있는데 어떤 문제가 있는지 찾을 수가 없다...

또 굴레에 빠져버린 것이다..

profile
개발, 정복
post-custom-banner

0개의 댓글