캐러셀!! 계속 구현해보고싶었는데 시간에 밀려 시도를 못해보다가 이번 MBTI 테스트 프로젝트를 만들면서 드디어 적용해봤다
기존 코드는 데스크탑 기준으로 너비나 배치 등을 적용해둬서 모바일로 확인했을 때 왼쪽과 같이 조각조각 잘리고 가려지고 ㅋㅋㅋ 이상한 배치가 됐다 반응형 UI도 꼭 적용해보고싶었기 때문에 아예 width 1024 이하인 경우에는 테스트에대한 가이드를 캐러셀로 보여주기로 했다.
구현 방법
1) 캐러셀로 보여줄 컨텐츠가 담긴 배열에서 인덱스를 증가/감소하며 해당하는 내용의 카드가 가운데에 오도록 한다
2) 이전, 다음 버튼을 눌렀을 때 0번 인덱스에서 이전 버튼을 눌렀거나, 마지막 인덱스에서 다음 버튼을 누른 경우 각각 마지막, 첫 인덱스로 변경한다.
3) 캐러셀이 보여지는 범위를 컨테이너로 감싸고, 컨테이너를 넘어서는 영역은 overflow-hidden으로 보여지지 않게 한다.
4) duration, ease-in-out (tailwind 사용)으로 동작이 지속되는 시간과 속도를 조절하고 translate로 이동할 위치를 지정한다.
다른 예시들을 참고해서 구현했지만 이해가 잘 되지않아 코드를 그림으로 그려 정리해봤다..
이렇게보니 이해가 된다!!
import { useState } from 'react';
import guideText from '../../data/guideText.js';
import GuidePanel from './GuidePanel.jsx';
import Button from '../Input/Button.jsx';
const Carousel = () => {
const [currentIndex, setCurrentIndex] = useState(0);
const handlePrev = () => {
setCurrentIndex((prevIndex) => (prevIndex === 0 ? guideText.length - 1 : prevIndex - 1));
};
const handleNext = () => {
setCurrentIndex((prevIndex) => (prevIndex === guideText.length - 1 ? 0 : prevIndex + 1));
};
return (
<div className='flex flex-col items-center'>
<div className='hidden lg:flex gap-5 mb-14'>
{guideText.map((guide, index) => (
<GuidePanel
key={index}
title={guide.title}
detail={guide.detail}
/>
))}
</div>
<div className='lg:hidden'>
<div className='relative w-full max-w-[400px] overflow-hidden'>
<div
className='flex transition-transform duration-500 ease-in-out'
style={{ transform: `translateX(-${currentIndex * 100}%` }}
>
{guideText.map((guide, index) => {
return (
<div
key={index}
className='flex-shrink-0 flex justify-center items-center w-full'
>
<GuidePanel
title={guide.title}
detail={guide.detail}
/>
</div>
);
})}
</div>
<Button
onClick={handlePrev}
className='absolute top-1/2 left-0 transform -translate-y-1/2 bg-gray-300 hover:bg-gray-400 text-white p-2 rounded-full'
>
◀
</Button>
<Button
onClick={handleNext}
className='absolute top-1/2 right-0 transform -translate-y-1/2 bg-gray-300 hover:bg-gray-400 text-white p-2 rounded-full'
>
▶
</Button>
</div>
<div className='flex justify-center mt-4 space-x-2'>
{guideText.map((_, index) => {
return (
<span
key={index}
className={`w-3 h-3 rounded-full ${currentIndex === index ? 'bg-blue-500' : 'bg-gray-300'}`}
></span>
);
})}
</div>
</div>
</div>
);
};
export default Carousel;
- 버튼 클릭 이벤트로 currentIndex를 업데이트
- 캐러셀 영역에서 보이지 않을 부분(현재 보여줄 가이드가 아닌 부분) 부모 요소에 overflow-hidden을 설정해 보이지 않게 함
- 가이드 영역은 부모요소 width의 100%만큼 차지하고 있으므로 인덱스 하나를 넘길 때마다 부모요소 width의 100%씩 이동하게 하면 가이드 영역 한칸의 이동이 됨
- transform: translateX를 이용해 x축 기준 어디에 위치할 것인지 지정하는 것이므로 currentIndex * 100 %만큼 이동하게 함 (0번 인덱스를 보여줄 땐 이동 x, 1번을 보여줄 땐 100% === 한 칸 만큼 왼쪽으로 이동)
- 순식간에 이동되지 않고 이동되는 과정이 보이는 것은 그 이동에 duration을 걸어두었기 때문!
'React' 카테고리의 다른 글
[React/Vite] 카카오맵 API 마커 표시, 클러스터 라이브러리 사용해보기 (1) | 2024.09.13 |
---|---|
[React/Vite] 카카오맵 API 사용 설정하기 (0) | 2024.09.13 |
[TanStack Query] Query Cancellation, Optimistic Updates (2) | 2024.09.07 |
[TanStack Query] useQuery() 옵션 - enabled, select (0) | 2024.09.06 |
UX 향상 기법 - Throttling & Debouncing, lodash (1) | 2024.09.06 |