퍼블리셔일 때 슬라이드 써야하는 일이 있으면 무조건 Swiper를 사용했었다.
React 환경에서는 처음 쓰는거라 기대 만빵
확실히 html, javaScript위에서 쓰는 것 보다 더 쉬웠음!!
$ npm install swiper
일단 위 명령어 쳐서 설치를 한다.
그리고 app.tsx 파일에 swiper에서 사용될 css를 import해야한다.
import 'swiper/css';
import 'swiper/css/pagination';
export default function App({ Component, pageProps }: AppProps) {
return (
...
);
}
그럼 Swiper 사용할 준비 완료 !!
import { Autoplay, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
const MainbannerSwiper = ({ mainBannerList }) => {
return (
<S.mainBannerSwiperBox>
<Swiper
modules={[Pagination, Autoplay]} // 페이지네이션, 자동재생 등의 기능을 불러옴
spaceBetween={50} // 슬라이더 간의 간격 지정
slidesPerView={1} // 한 슬라이더 당 보여져야하는 슬라이드 갯수
// 슬라이더가 변경될 때 마다 특정 event를 받아올 수 있음
// activeIndex는 현재 active되어 있는 슬라이더의 index를 의미함. animation추가할 때 필요함.
onSlideChange={(e) => setActiveIndex(e.activeIndex)}
autoplay={{ // 자동 재생
delay: 4500, // 지연 시간 (한 슬라이더에 머물르는 시간)
disableOnInteraction: false, // 마우스 제어 이후 자동 재생을 막을지 말지
}}
speed={500} // 슬라이더 넘어가는 속도
pagination={{ // 페이지네이션 활성화
clickable: true, // 페이지네이션 버튼 클릭 가능하게 할지 말지
}}
>
... // 각 슬라이더마다 필요한 내용을 담음
</Swiper>
</S.mainBannerSwiperBox>
);
};
export { MainbannerSwiper };
아주 쉽다.
Swiper 컴포넌트를 활용해서 구현이 가능하다.
각종 옵션은 공식 사이트를 참고하자.
저렇게만 코드를 짜도, Swiper는 기본 pagination을 제공한다.
하지만 대부분 실무에서는 당연히 디자이너가 요구하는 사항이 다를거고 커스텀이 필요하다.
그래서 나는 기본 Swiper가 제공하는 className에 접근해서
css를 직접 수정하는 방향으로 커스텀해 보았다.
import { css } from 'styled-components';
export const SwiperPaginationReset = css`
/* 페이지네이션 위치 잡기 */
right: 15px;
bottom: 15px;
left: auto;
width: auto;
/* 페이지네이션 커스텀 */
.swiper-pagination-bullet {
background-color: ${({ theme }) => theme.color.gray_BDBDBD};
}
/* 현재 선택되어있는 페이지네이션 요소 커스텀 */
.swiper-pagination-bullet-active {
background-color: ${({ theme }) => theme.color.white_FFFFFF};
}
`;
우선, pagination 초기화 css는 여기저기 많이 사용될 것 같아서
공통 css를 생성해 주었다.
import styled from 'styled-components';
import { SwiperPaginationReset } from '@shared/ui/styles/utills';
export const mainBannerSwiperBox = styled.div`
...
.swiper-pagination {
${SwiperPaginationReset}
}
`;
onSlideChange
메서드를 활용해서 active되었을 때 마다 className을 추가해
해당 className을 가진 slider의 텍스트들이 애니메이션 처리될 수 있도록 하였다.
...
const MainbannerSwiper = ({ mainBannerList }: MainBannerProps) => {
const [activeIndex, setActiveIndex] = useState(0);
return (
<S.mainBannerSwiperBox>
<Swiper
// 1. active된 슬라이더의 index를 받아서 setActiveIndex에 저장한다.
onSlideChange={(e) => setActiveIndex(e.activeIndex)}
...
>
{mainBannerList.map((banner) => (
<SwiperSlide key={banner.id}>
<Image src={banner.imageSrc} alt={banner.title} fill sizes='1195px' priority />
// 2. 슬라이드 내용 id와 active id가 같으면 className 추가
<div className={`description-box ${banner.id === activeIndex ? 'active' : ''}`}>
...
</div>
</SwiperSlide>
))}
</Swiper>
</S.mainBannerSwiperBox>
);
};
export { MainbannerSwiper };
슬라이더는 위와 같이 작성해 주었다.
import styled from 'styled-components';
import { SwiperPaginationReset } from '@shared/ui/styles/utills';
export const mainBannerSwiperBox = styled.div`
...
&.active {
h2 {
transform: translateX(0);
opacity: 1;
}
p {
transform: translateX(0);
opacity: 1;
}
button {
transform: translateX(0);
opacity: 1;
}
}
}
`;
css active 상태에 대한 애니메이션 효과 추가
위 gif처럼 custom이 완료되었다!!! 🪄
이번에는 이런 네비게이션 디자인을 구현해 보겠다.
네비게이션 화살표는 onSlideChange
와 onSwiper
메서드를 활용해서 커스텀할 수 있다.
<Swiper>
...
</Swiper>
// 커스텀 버튼 추가
<S.NavigationLeft>
<RoundedArrowButton disabled={isBeginning} handleClick={handlePrev} direction='left' />
</S.NavigationLeft>
<S.NavigationRight>
<RoundedArrowButton disabled={isEnd} handleClick={handleNext} direction='right' />
</S.NavigationRight>
우선 우리가 만들어 둔 Swiper 하단에 커스텀 버튼 컴포넌트를 넣어주었다.
RoundedArrowButton
는 그냥 단순히 동그란 화살표 모양의 컴포넌트임.
디자인 컴포넌트를 넣어주던가, 아니면 그냥 button으로 제어해도 좋음.
...
const [swiper, setSwiper] = useState<SwiperClass>();
const [isBeginning, setIsBeginning] = useState(true);
const [isEnd, setIsEnd] = useState(false);
const handlePrev = () => {
// 이전으로 이동
swiper?.slidePrev();
};
const handleNext = () => {
// 다음으로 이동
swiper?.slideNext();
};
<Swiper
...
onSlideChange={(e) => {
// 시작 슬라이더인지 아닌지 boolean 반환
setIsBeginning(e.isBeginning);
// 마지막 슬라이더인지 아닌지 boolean 반환
setIsEnd(e.isEnd);
}}
onSwiper={(e) => {
setSwiper(e);
}}
>
...
</Swiper>
...
onSlideChange
: slider 가 바뀔 때 마다 마지막 슬라이드인지, 시작 슬라이드인지 체크해서 state에 담아두고, navigation의 활성/비활성화 버튼 구현에 이용할 것임.
onSwiper
: 슬라이드 생성될 때 Swiper 이벤트(메서드) 정보들을 모두 state에 저장해 둔다. 그리고 onClick이 될 때 마다 next/prev에 맞는 메서드를 연결시켜주는 역할을 한다.
버튼이 disabled 처리가 잘 되고 있는 것을 확인할 수 있다.
너무 쉽고 재밌다.
Swiper 정말 오랜만에 쓰는데 ...
여전히 개발자들에게 묵묵히 도움을 주고 있었구나 🥲
오랜칭구 다시 만난 기분 ㅋㅎ