쇼핑몰 제작기 - Image Slider 만들기 (Carousel)

Sunflo·2023년 3월 10일
0

쇼핑몰 제작기

목록 보기
2/3
post-thumbnail

쇼핑몰에 필요한 기능인 Image Slider를 만들어보았다.
배너와 상품리스트에 Image Slider 기능을 넣어주면 홈 화면을 좀 더 알차게 만들 수 있을 것 같다.

Image Slider가 좀 더 와닿지만 이 기술의 실제 이름은 Carousel이다.

회전 목마라.. Slider가 훨씬 정확한 표현같은데.. 아무튼 Carousel 이라고 쓰이는걸 알아두자!

구현

나는 Carousel 안의 이미지 위에서 글자가 이동하는 기능도 구현했다.

import React, { useEffect, useState } from "react";

export default function Test() {
  const [isMove, setIsMove] = useState(false);
  const [slider, setSlider] = useState(1);
  const [isTransition, setIsTransition] = useState(true);

  const prev = () => {
    setSlider((v) => v - 1);

    setIsMove(false);
    setTimeout(() => setIsMove(true), 2000); // 애니메이션 시간 후 상태 초기화
  };

  const next = () => {
    setSlider((v) => v + 1);

    setIsMove(false);
    setTimeout(() => setIsMove(true), 1000); // 애니메이션 시간 후 상태 초기화
  };

  useEffect(() => {
    setIsMove(true);
  }, []);

  useEffect(() => {
    if (slider === 4) { // 마지막 이미지일때
      setTimeout(() => {
        setIsTransition(false); // 이미지의 이동이 끝나는 시간 1초에 맞춰 1초뒤 transition을 끈다.
        setSlider(1);
      }, 1000);

      setTimeout(() => {
        setIsTransition(true); // 2초뒤 transition을 다시 킨다.
      }, 2000);
    }

    if (slider === 0) { // 첫번째 이미지일때
      setTimeout(() => {
        setIsTransition(false);
        setSlider(3);
      }, 1000);

      setTimeout(() => {
        setIsTransition(true);
      }, 2000);
    }
  }, [slider]);

  return (
    <>
    	// Viewer
      <div className="w-section ">
    	// Slider
        <div
          className={`flex w-slider 
            translate-x-section${slider}
           ${isTransition && "duration-1000"}`}
        >
			// 이미지들
          <PrevImage isMove={isMove} />
          <Images isMove={isMove} />
          <NextImage isMove={isMove} />
        </div>
      </div>
      <button onClick={prev}> 이전</button>
      <br />
      <button onClick={next}> 다음</button>
    </>
  );
}

const Images = ({ isMove }) => {
  return (
    <>
      <div className={`w-section h-40  bg-blue-500`}>
        {/* 이게 이미지에 애니메이션이 적용되는거지 */}
        <p
          className={`  duration-1000 mb-2 bg-red-500 ${
            isMove ? "translate-x-0 opacity-100" : "translate-x-40 opacity-20"
          }`}
        >
          Click Me
        </p>
      </div>
      <div className={`w-section h-40  bg-green-500`}>
        {/* 이게 이미지에 애니메이션이 적용되는거지 */}
        <p
          className={`  duration-1000 mb-2 bg-red-500 ${
            isMove ? "translate-x-0 opacity-100" : "translate-x-40 opacity-20"
          }`}
        >
          Click Me
        </p>
      </div>
      <div className={`w-section h-40  bg-yellow-500`}>
        {/* 이게 이미지에 애니메이션이 적용되는거지 */}
        <p
          className={`  duration-1000 mb-2 bg-red-500 ${
            isMove ? "translate-x-0 opacity-100" : "translate-x-40 opacity-20"
          }`}
        >
          Click Me
        </p>
      </div>
    </>
  );
};

const PrevImage = ({ isMove }) => {
  return (
    <div className={`w-section h-40  bg-yellow-500`}>
      <p
        className={`  duration-1000 mb-2 bg-red-500 ${
          isMove ? "translate-x-0 opacity-100" : "translate-x-40 opacity-20"
        }`}
      >
        Click Me
      </p>
    </div>
  );
};

const NextImage = ({ isMove }) => {
  return (
    <div className={`w-section h-40  bg-blue-500`}>
      <p
        className={`  duration-1000 mb-2 bg-red-500 ${
          isMove ? "translate-x-0 opacity-100" : "translate-x-40 opacity-20"
        }`}
      >
        Click Me
      </p>
    </div>
  );
};

일단 Carousel은 아래와 같은 조건이 필요하다.
1. Image를 보여줄 Viewer
2. Image를 움직일 Slider
3. 보일 Image들(오리지널이라고 하겠다) ex) Image1, Image2, Image3
4. 'Image1'일 때 '이전'으로 움직이면 보일 이미지 (Image3)
5. 'Image3'일 때 '다음'으로 움직이면 보일 이미지 (Image1)
여기까지 Image는 이렇게 배치된다. [Image3 [Image1 Image2 Image3] Image 1]
Image 3개를 보이고싶으면 이렇게 5개의 Image를 배치해야한다. (보이고싶은 Image 수 + 2만큼)
6. 조건 4,5의 Image가 Viewer로 보여지면 transition을 잠시 끄고 해당하는 오리지널 Image로 위치시킨다.
ex) 조건 4에 해당하는 Image는 Image3이다 -> 이전버튼을 눌러 조건 4인 Image3이 보여지면 transition을 꺼서 이동하는걸 안보이게 하고 오리지널 Image3의 위치로 이동한다.

추가적으로 글자가 움직이게 하려면 아래와 같은 조건이 필요하다.
1. 슬라이드 state와 글자가 움직이는 state가 따로 존재하고,
슬라이드가 이동할때마다 글자가 움직이는 state를지 초기화 해줘야한다.

결과

헤맷던 점

1. React 스럽게 만들기

JS로 한번 만들어봤는데 React로 만들려니 또 다른 맛이 느껴졌다.
CSS에 useState와 useEffect를 적용해서 만든다는 생각자체가 아직은 낯설다. 그래도 점점 나아지는게 느껴진다.
방식이 아직 낯설뿐 이걸 구현하려면 어떤 Hook이 필요하겠구나는 바로바로 생각이 났다.

2. tailwindcss.. 이런 문제가?!

일단 내가 잘못 사용한 것일 수도 있다
tailwindcss에서 custom-translate-x를 동적으로 적용하기전에 미리 입력을 해봐야 한다는걸 몰라서 헤맷다.
나는 slider값을 바꿔가며 translate-x-section${slider} 이렇게 동적으로 translate-x를 적용했다.
근데 이걸 하려면 translate-x-section1, translate-x-section2, translate-x-section3 이걸 한번씩은 직접 실행을 해야한다.
분명 이 코드가 맞는데 왜 안되지? 하다가 이런 이유란걸 알게됐을땐 어이가 없었다.
tailwindcss 편하긴 한데 이런점은 좀 별로다.
배포했을 때 이게 어떻게 될런지...
프로젝트에는 transltate를 tailwind안쓰고 그냥 css에 했다.

3. 이미지에 따른 로딩문제?? 렌더링 성능문제??

이렇게 만든 Carousel을 프로젝트에 적용을 했더니 다 잘 됐다.
하나만 빼고!!!
제일 처음에 '이전,다음' 버튼을 누르면 약 1초 정도의 딜레이 후 작동했다. 그 뒤로는 딜레이 없이 잘 작동한다.
왜 그런가 하고 1시간은 코드만 본 것 같다. 원인은 이미지였다.
총 3개의 이미지 중 한개씩만 넣어서 슬라이드를 작동해봤는데
첫번째 이미지만 딜레이가 없고, 나머지 두 이미지는 딜레이가 있었다.
심지어 두 이미지의 딜레이가 각각 달랐다.
이미지로만 테스트를 해서 일단 이미지에 문제가 있다는 것을 알았고,
다시 원래의 코드로 해보니 이미지만 했을 때 보다 딜레이가 커졌다.
아무래도 성능 문제인것 같다.
큰 모니터에서 하면 이런 문제가 없는데 작은 모니터에서 하면 이런 문제가 발생한다...
이건 따로 글을 써야겠다.

profile
뭐든지 할 수 있고, 뭐든지 될 수 있다.

0개의 댓글