프로젝트를 진행하면서 캐러셀을 만들어야 하는 이슈가 있었다. React에 slick과 같은 다양한 캐러셀 라이브러리가 있기 때문에 라이브러리를 사용하려고 했지만, 커스텀하는 것이 하나같이 쉽지 않았고, examples에서 내가 원하는 디자인들은 없었기 때문에 직접 구현을 해보려고 생각했다. (구현도 정말 쉽지 않았다.)
우선 내가 구현하는 캐러셀의 간단한 요구명세를 작성해보겠다.
- 캐러셀은 한번에 최대 세 개 요소까지 볼 수 있다.
- 선택된 요소는 가장 중간에 있어야 하고, 크기도 다른 요소에 비해 커야 한다.
- 첫 번째 사진은 항상 중간에 위치해야 한다.
- Infinity / Auto Scrolling은 필요하지 않다.
- 선택된 요소에 따라 하단에 값들이 달라져야 한다 (사진상에는 확인되지 않음)
- 이동할 때 애니메이션이 필요하다
요구 명세를 봤을 때, 1번, 2, 4번 요소는 slick으로도 쉽게 수정할 수 있는 부분이었지만 나머지 부분에서 커스텀이 어려워 보였기 때문에 공부할 겸 + 기능적 요소를 추가할 때 쉽게 추가하기 위하여 직접 캐러셀을 구현하였다.
캐러셀을 직접 구현하는 다양한 글을 봤을 때, 많은 박스를 가로로 정렬하고 하나 또는 세 개의 박스만 한 번에 보이도록 overflow : hidden 옵션을 통해 구현한 것을 많이 보았다.
이를 활용해 처음에 시도했던 방법은 Grid를 활용한 방법이었다. auto-fit 옵션을 통해 데이터가 많아져도 over-flow를 숨길 수 있었고, props를 통해 어떤 column에 위치할지 정해주고, 중간 칼럼의 크기를 크게 준다면 쉽게 레이아웃을 배치할 수 있을 것 같았다. 하지만, 내 생각처럼 되지 않았다.
물론, 위에 말처럼 원하는 레이아웃은 쉽게 짤 수 있었지만, 캐러셀에 가장 중요한 부분인 애니메이션 효과를 줄 수 없었다.
될 것 같은데...라고 생각하며 stack-overflow를 찾아봤지만 바로 이해할 수 있었다. 'grid-column : 2.5/3.5를 렌더링 할 수 있는가? ' 눈속임 코드를 짜지 않는 이상 불가능했다.
지금이라도 slick을 공부해서 도전해보는 게 빠른가 고민하다가 아이디어가 떠올랐다.
위에 말(가로로 배치하여 overflow:hidden 하는 방식)에 너무 매몰되어서 react props와 styled-component를 통해 보여주고 싶은 것만 보여줄 수 있다는 것을 잊고 있었다.
두 번째로 도전한 방법은 useState와 styled-components 만을 사용하여 만들어 낸 방식이다.
useState를 통해 현재 선택된 슬라이드를 확인하고, 그 슬라이드 인덱스와 인덱스가 1만큼만 차이나는 슬라이드만 렌더링 해주는 방식이다.
코드는 두 개의 jsx파일로 만들었는데, Carousel의 Container부분, 하나는 Carousel의 Slider부분이다.
먼저 Container의 코드는 아래와 같다
const Container = styled.div`
position: relative;
margin: auto;
width: 70%;
max-width: 800px;
height: 80%;
`;
function MainCarousel() {
const slider = [
{ id: 0, bg: "https://picsum.photos/200/300" },
{ id: 1, bg: "../../img/plus.png" },
];
const [currentSlide, setCurrentSlide] = useState(0);
const total = slider.length;
console.log(total);
function goNext() {
if (currentSlide + 1 < total) setCurrentSlide((val) => val + 1);
}
function goPrev() {
if (currentSlide > 0) setCurrentSlide((val) => val - 1);
}
function check(id) {
if (id + 1 === currentSlide) {
return "prev";
} else if (id - 1 === currentSlide) {
return "next";
} else if (id === currentSlide) {
return "now";
} else {
return "hidden";
}
}
return (
<>
<button onClick={goPrev}>앞</button>
<button onClick={goNext}>뒤</button>
<Container>
{slider.map((val) => {
return <Slider key={val.id} check={check(val.id)} bg={val.bg} />;
})}
</Container>
</>
);
Slider라는 컴포넌트에 할당받은 value가 어느 위치인지에 대한 정보와 렌더링 해야 하는 값을 알려줬다. absolute를 활용해 레이아웃을 줄 것이기 때문에 Contrainer에 relative를 준 것을 확인할 수 있다.
Slider의 코드는 아래와 같다.
const NowSlider = styled.div`
width: ${(props) => (props.check === "now" ? "30%" : "25%")};
padding-top: ${(props) => (props.check === "now" ? "30%" : "25%")};
border-radius: 50%;
transform: translate(-50%, -50%);
transition: all ease-in-out 0.5s;
position: absolute;
top: 50%;
left: ${(props) =>
(props.check === "now" && "50%") ||
(props.check === "next" && "80%") ||
(props.check === "prev" && "20%")};
background-image: url(${(props) => props.bg});
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
`;
function Slider({ check, bg }) {
console.log(check);
return (
<>
{check !== "hidden" ? (
<NowSlider bg={bg} check={check}></NowSlider>
) : null}
</>
);
}
Styled-components를 활용하여 조건에 따른 CSS를 주었다.
내가 고민한 것과는 무색하게 훨씬 쉽게 코드를 만들어 낼 수 있었고 완성된 결과는 아래와 같다.
(공부하면서 직접 생각해낸 코드이기 때문에, 부족한 부분이 많이 있을 수 있습니다)
'개발' 카테고리의 다른 글
[R3F] R3F 연습하기 ref를 활용한 움직임 (0) | 2022.09.08 |
---|---|
[R3F] React-Three-Fiber 연습하기_기본예제 (0) | 2022.09.05 |
[REACT] 조건부 렌더링 (0) | 2022.07.27 |
[Git] Git에서 React 폴더에 들어가지 못 하는 이유 (0) | 2022.07.15 |
[CSS] CSS Grid 행 화면에 고정하기 (By sticky) (0) | 2022.06.26 |