개요
Carousel을 만드는 과제를 하면서 이것저것 많이 보고 이 정도까지 열심히 만들어봤는데...
생각보다 퀄리티가 많이 부족해서 쓰지 않고 react-slick이라는 라이브러리를 사용하였습니다.
이번 포스트에서는 아쉬운 맘을 담아 제가 만들던 코드를 올리고, react-slick의 설치부터 제작까지 진행하며 유용했던 정보, 꼭 알아야할 정보를 적고자 합니다.
본론
1. Carousel 직접 제작
1.1) 도움이 많이 된 글 모음
- Carousel 개념 잡는데 좋았던 글 (1)
- Carousel 개념 잡는데 좋았던 글 (2)
- Transition 개념 익히는데 많이 도움이 되었던 글
- Web관련 헷갈렸던 개념을 바로잡기 좋은 사이트
- Event에 관한 개념을 잡는데 도움된 글
1.2) 내가 만든 Carousel 코드
transitionX와 반응형에 맞춰 size별로 나눠 width와 height를 바꾸려다보니 일이 커져서...
그냥 코드만 올려둡니다...! 유튜브 영상처럼 작동은 해요! 다만 auto를 할때 슬라이드를 하면 속도가 이상해진다거나 width와 height를 작은 사이즈로 했을때 transitionX의 값이 올바르지 않아서 시간 관계상 다음 기회로 미뤄두려합니다.
// index.stories.tsx (스토리북에서 보기 위해 만든 예시)
export const DefaultCarousel = (args: ComponentStory<typeof Carousel>) => {
const imgLists = [
{
idx: 0,
image: '/imgs/Carousel.png',
alt: 'happy carousel',
onClick: () => {
alert('Carousel');
},
},
{
idx: 1,
image: '/imgs/Carousel2.png',
alt: 'sad carousel',
onClick: () => {
alert('Carousel2');
},
},
{
idx: 2,
image: '/imgs/Carousel3.png',
alt: 'haha carousel',
onClick: () => {
alert('Carousel3');
},
},
{
idx: 3,
image: '/imgs/Carousel3.png',
alt: 'haha caroul',
onClick: () => {
alert('Carousel4');
},
},
{
idx: 4,
image: '/imgs/Carousel3.png',
alt: 'ha carousel',
onClick: () => {
alert('Carousel5');
},
},
];
return (
<GlobalThemeProvider theme={theme}>
<Carousel device={'md'} imgLists={imgLists} auto={true} {...args} />
</GlobalThemeProvider>
);
};
// index.tsx (실제 로직이 있는곳.)
import React, { useEffect } from 'react';
import { StyledCarouselItem, StyledCarousel, SCarouselItemProps } from './style';
export interface CarouselItemProps extends SCarouselItemProps {
src: string;
alt?: string;
onClick?: (e: React.MouseEvent) => void;
}
export const CarouselItem = ({ device, src, onClick, alt }: CarouselItemProps) => {
return <StyledCarouselItem device={device} src={src} onClick={onClick} alt={alt} />;
};
// imgitem의 타입선언 (Carousel안에서 img를 담는 CarouselItem이 필요로할거...)
export type ImgItem = {
idx: number;
image: string;
alt: string;
onClick: (e: React.MouseEvent) => void;
};
// 전체 Carousel용 props
export interface CarouselProps {
auto?: boolean;
imgLists: ImgItem[];
}
const Carousel = ({ device, auto, imgLists }: CarouselProps & SCarouselItemProps) => {
// Variables
const size = imgLists.length;
const [currentIdx, setCurrentIdx] = React.useState(size / 2);
const transRatio = 100 / size;
const [transX, setTransX] = React.useState(size % 2 === 0 ? -transRatio / 2 : transRatio);
// 페이지 전환
const nextPage = () => {
let move = transX - transRatio;
if (move < -50) move += 100;
setTransX(move);
setCurrentIdx(currentIdx + 1);
};
const prevPage = () => {
let move = transX + transRatio;
if (move > 50) move += -100;
setTransX(move);
setCurrentIdx(currentIdx - 1);
};
const ScrollHandler = (e: React.WheelEvent) => {
if (e.deltaY >= 400) nextPage();
else if (e.deltaY <= -400) prevPage();
};
// Item 생성 함수
const createItem = ({ idx, image, alt, onClick }: ImgItem) => {
return (
<StyledCarouselItem device={device} key={idx} src={image} onClick={onClick} onWheel={ScrollHandler} alt={alt} />
);
};
// 자동재생 기능
useEffect(() => {
if (!auto) return;
setTimeout(() => {
nextPage();
}, 3000);
});
// Carousel로 반환될 내용
return (
<React.Fragment>
<StyledCarousel translateX={transX} hidden>
{imgLists.map(imgList => createItem(imgList))}
</StyledCarousel>
</React.Fragment>
);
};
export default Carousel;
import styled from '@emotion/styled';
import theme from '../../../styles/theme';
const carouselTheme = theme.style.carousel;
export interface SCarouselProps {
translateX: number;
}
const changePage = ({ translateX }: SCarouselProps) => {
return `
transform: translateX(${translateX}%);
`;
};
export const StyledCarousel = styled.div`
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: stretch;
transition-duration: 400ms;
${changePage};
`;
export interface SCarouselItemProps {
device: 'sm' | 'md' | 'lg';
}
const setSize = ({ device }: SCarouselItemProps) => {
return `
width: ${carouselTheme.width[device]};
height: ${carouselTheme.height[device]};
`;
};
export const StyledCarouselItem = styled.img`
margin: 0 1rem;
cursor: pointer;
flex-basis: 50vw;
${setSize};
`;
아마 99%의 확률로 저 코드는 별로일거예요... 그냥 지금 이 피곤하고 머리안돌아가는 상태로도 알수있습니다... 그냥 아래 링크들에 가서 좋은 정보 많이 가져가셨으면합니다...
2. Carousel Library 사용
1) 유용한 Carousel Library 후보들
- Slick http://kenwheeler.github.io/slick/
- Swiper https://swiperjs.com/
- Flickity https://flickity.metafizzy.co/
- Keen-Slider - 부드러운 HTML 터치 슬라이더 : https://news.hada.io/topic?id=2299
2) react-slick
React-slick의 많은 사용량과 autoplay제공, 편리한 사용방법, 다양한 예시를 보고 사용하기로 결정했습니다.
사용량이 많다는 건 그만큼 자료가 많기에 비교적 난이도가 낮아진다는 점. 이를 이용해 빠르게 설치를 해봤습니다.
3) react-slick 설치 방법
저는 yarn berry 사용 + typescript와 react를 사용하는 프로젝트였기 때문에 아래와 같이 입력해줬습니다.
$ yarn add react-slick -D
$ yarn add slick-carousel -D
$ yarn add @types/react-slick -D
4) react-slick의 style 설정 정리된 글
slick의 공식 페이지보다 더 이해하기 편하게 settings의 type과 event, method를 설명해준 글입니다! (다음에 carousel을 다시한번 구현해야할 상황이 온다면 해당 글은 꼭 재방문할 것 같네요!!)
팀원 분들이 이해하시기 좋도록 PR올리며 적어둔 제가 사용한 settings 값들입니다. 참고하시면 좋을 것 같아요 :)
const settings = {
// 무한으로 돌것인가 (false면 마지막 페이지에 갔을때 첫페이지로 전환 X)
infinite: true,
// 전환되는 속도 (transition과 유사)
speed: 1000,
// 한 Slide안에서 보여줄 사진의 개수
slidesToShow: 1,
// 한번의 Scroll로 넘어갈 슬라이드의 개수
slidesToScroll: 1,
// 현재 슬라이드를 중앙에 둘지 여부
centerMode: true,
// 현재 슬라이드 좌우로 줄 패딩값 ( +면 양옆의 슬라이드가 보임, - 면 양옆의 사진이 안보이도록 함)
centerPadding: '-3px',
// 자동재생여부
autoplay: true,
// 자동재생 속도
autoplaySpeed: 2500,
// 아래 점으로 몇번째 슬라이드인지 보여주는 점의 가시 여부
dots: true,
// 반응형으로 처리할 셋팅값의 요소
responsive: [
{
breakpoint: 600, // 600px이하가 되면
settings: {
dots: false, // 점을 안보이게 하겠다.
},
},
],
};
5) slick-carousel의 css
해당 부분을 import해주지 않으면 react-slick을 만들었을때 이게 뭐지????? 싶을겁니다(경험담). 꼭 import해주세요!!
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
slick-carousel에는 여러 클래스가 있습니다. 제 경우에는 블로그를 돌아다니다 그냥 node_modules를 탐색해 클래스 설정 내용을 프로젝트에 맞춰 수정해봤어요. node_modules/slick-carousel/slick/slick.css와 node_modules/slick-carousel/slick/slick-theme.css을 참고하시면 carousel을 만들며 사용된 요소들의 css값을 확인하실 수 있습니다!
제가 설정한 slick의 클래스명은 slick-track, slick-list, slick-slide, slick-dots였습니다. 이런 구조로 보이는거라 생각하고 값을 설정하였습니다.
6) carousel 속 Img의 크기 설정 (object-fit)
Carousel의 요구사항은 wanted와 비슷하게 작동하되 서비스의 특성에 맞춰 진행하는 것이었습니다. 첫번째 사진처럼 인물이 중앙에 있고 웹 페이지의 크기에 맞춰 중앙 부분이 잘려나오도록 만들어야 했습니다.
wanted처럼 carousel의 반응형을 구현하고자 600px이하로 내려가면 object-fit에 none을 줘 사진이 중앙기준으로 크기에 맞춰 설정되도록 변경하였고, 해당 글이 많은 도움이 되었습니다.
6) Slick과 Styled Component를 같이 쓰고자 참고한 사이트
정리가 잘되어있어서 많이 참고했어요
마무리
결과물!
'Language > Javascript' 카테고리의 다른 글
[react] timepicker 관련 라이브러리 + 찾아보다 알게된 컴포넌트 공유 사이트 (0) | 2022.05.01 |
---|---|
[styled Component] Styled Component로 custom dropdown 만들기 (0) | 2022.04.11 |
[자바스크립트] String을 number로 바꾸는 법 (0) | 2021.09.26 |
[JS, JavaScript] document.getElementById()를 이용해 값을 바꾸려했는데 반영이 안됨. (부제 : 생일 Dday 출력하기) (0) | 2021.04.28 |