stacked card slider 구현하기(react, styled-component)
디자이너님에게 아래에 있는 card slider처럼 stacked card slider를 구현해달라는 요청을 받았다.
그동안 슬라이드를 구현할 때 react-slick 라이브러리로 구현했는데 stacked card slider는 react-slick로 구현할 수 없었다.
react-slick의 verticalSwipeToSlide를 활용해볼까도 했지만 라이브러리가 너무 망가져서 슬라이더가 오히려 이상해지기만 했다.
구글링을 통해 codepen에서 html, css, jQuery로 구현된 좋은 예시를 발견했고
이 코드를 내 코드로 녹여 구현할 수 있었다.
https://codepen.io/akramurridjal/pen/VwwrGVY
Stacked card slider JS
...
codepen.io
- 내가 구현한 stacked card slider
3.5초마다 자동으로 다음장으로 넘어가며 슬라이더를 클릭하거나 아래의 dot을 클릭해도 넘어간다.
- stacked card slider 구현기
나는 카드가 총 3개여서 그 3개의 카드를 구현하기 위해
const [indexes, setIndexes] = useState<number[]>([0, 1, 2]);
const images = [StakingImg.ad1, StakingImg.ad2, StakingImg.ad3];
일단 이렇게 indexs state를 만들고 그 index에 맞게 images에서 알맞은 이미지를 꺼내오는 로직을 생각했다.
<CardsWrapper onClick={handleClick}>
{[0, 1, 2].map((i) => (
<Card key={i} index={images[i]} data-slide={indexes.indexOf(i)} />
))}
</CardsWrapper>
이런식으로 indexs를 map으로 돌려 index props에 넣어주고
사용자 지정 속성인 data-slide에도 indexes 배열에서 각 카드의 위치를 나타내는 인덱스를 찾아 data-slide 속성으로 할당하여
각 카드가 현재 표시되는 위치를 알 수 있게 했다.
data-slide 속성은 각 카드의 위치를 식별하는 데 사용된다.
1. 쌓여진 카드 레이아웃 구현하기
data-slide 속성은 CSS 선택자에서도 사용될 수 있는데 쌓여진 카드 레이아웃을 구현하기 위해 나는 이렇게 사용했다.
&[data-slide="0"] {
transform: translate(0px, 0px) scale(1);
z-index: 4;
opacity: 1;
}
&[data-slide="1"] {
transform: translate(0px, -35px) scale(0.9);
z-index: 3;
opacity: 0.6;
}
&[data-slide="2"] {
transform: translate(0px, -70px) scale(0.8);
z-index: 2;
opacity: 0.3;
}
2. 슬라이드 카드를 다음 순서로 이동시키기
handleClick 함수는 슬라이드 카드를 다음 순서로 이동시키는 함수이다.
현재 인덱스 배열인 indexes를 변경하여 각 카드의 순서를 업데이트해준다.
indexes 배열을 스프레드 연산자로 새로운 배열에 복사하고 첫 번째 인덱스를 shift 메서드를 사용하여 삭제한 다음,
그 인덱스를 마지막 위치에 추가하는 로직이다.
이렇게 인덱스 배열을 업데이트하면, 카드가 순서대로 이동하게 되는 것이다.
const handleClick = () => {
setIndexes((indexes: number[]) => {
const newIndexes = [...indexes];
const firstIndex = newIndexes.shift();
newIndexes.push(firstIndex!);
return newIndexes;
});
};
useEffect(() => {
const interval = setInterval(() => {
handleClick();
}, 3500);
return () => clearInterval(interval);
}, []);