저장해두면 언젠가 쓸까해서 저장해두는 나의 커스텀 crousel
만들때는 참 오래걸렷는데 버리는 것도 한순간이군
사용 방법
- ReactElement[] | ReactElement 형식의 children 을 받아 배열의 경우 매핑하여 슬라이드 배치
- 추가로 필요한 banner 가 있다면 받아서 배치 (딱히 필요없음)
- props 로 styleOption:{ height:CssValue } 받아 crousel 높이 설정 (width 는 자동으로 100% 상위 태그로 감싸서 넓이 조정하여 사용하는 방식)
- CssValue 는 따로 css 를 props 를 입력받을때 타입을 자세히 설정해두려고 만든 class 형식의 type 이며 간단하게 string 으로 조금 고쳐서 사용해도 상관없다.
보완점
- css 입력 받는 부분이 CssValue 로 통일돼있지 않는데 일부 컨텐츠 사이즈를 입력받는 부분에서 실제로 넓이관려해서 계산하는 부분 때문이다.
- 기능 부족
특징 정리
- 화면 resize 에 대응하여 넓이 조정됨
- 자동 넘기기 기능
- 슬라이드 넘기는 버튼 존재
import React, { ReactElement, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
import styled from 'styled-components';
import AngleRight from '@svgs/angle-right.svg' // 좌측 버튼 이미지 소스
import AngleLeft from '@svgs/angle-left.svg' // 우측 버튼 이미지 소스
const AppLayout = styled.div`
width: 100%;
`
const CarouselContainor = styled.div`
position: relative;
`
const CarouselBox = styled.div<{ height:CssValue }>`
width: 100%;
height: ${({ height }) => height.getValue()};
margin: 30px 0;
`
const CarouselView = styled.div`
width: 100%;
height: 100%;
position: relative;
overflow-x :hidden;
`
const CarouselTrack = styled.div<{ contetWidth:number, currentSlide:number }>`
width: ${({ contetWidth }) => `${contetWidth.toString()}px`};
height: 100%;
position: absolute;
transform: translateX(${({ contetWidth, currentSlide }) => `${(contetWidth * currentSlide * -1).toString()}px`});
left: 0;
top: 0;
display: flex;
transition: all 1s ease-in-out;
`
const CarouselButton = styled.div`
position: absolute;
top:50%;
transform: translate(0, -50%);
z-index: 10;
width: auto;
height: auto;
img{}
&.prev{left: 0px;}
&.next{right: 0px;}
`
const SlidePage = styled.div<{ contetWidth:number }>`
position: relative;
min-width: ${({ contetWidth }) => `${contetWidth.toString()}px`};
height: 100%;
`
interface CarouselProps {
styleOption:{
height:CssValue
},
banner?: ReactElement,
children: ReactElement[] | ReactElement;
}
function isReactElements(arg: any): arg is ReactElement[] {
return arg.length !== undefined;
}
const Carousel = ({ styleOption, banner, children }:CarouselProps) => {
const [currentSlide, setCurrentSlide] = useState(0)
const [isAutoPlay, setIsAutoPlay] = useState(true)
const [boxSize, setBoxSize] = useState<number>(0)
const carouselBoxRef = useRef<HTMLDivElement>(null)
const timer = useRef<NodeJS.Timeout>()
// 다음 슬라이드로 이동
const next = useCallback(() => {
if (!isReactElements(children)) return
if (currentSlide >= children.length - 1) {
setCurrentSlide(0)
} else {
setCurrentSlide(currentSlide + 1);
}
}, [currentSlide, children])
// 이전 슬라이드로 이동
const prev = useCallback(() => {
if (!isReactElements(children)) return
if (currentSlide === 0) {
setCurrentSlide(children.length - 1)
} else {
setCurrentSlide(currentSlide - 1);
}
}, [currentSlide, children])
const pause = useCallback(() => setIsAutoPlay(false), [])
const start = useCallback(() => setIsAutoPlay(true), [])
// 자동 넘기기 기능
useEffect(() => {
clearTimeout(timer.current)
if (isAutoPlay) timer.current = setTimeout(next, 2000)
}, [next, isAutoPlay])
// 가변적인 화면사이즈 대응
useLayoutEffect(() => {
setBoxSize(carouselBoxRef.current?.offsetWidth ?? 0)
}, [carouselBoxRef.current?.offsetWidth])
return (
<AppLayout>
<CarouselContainor>
<CarouselButton key="prev" className="prev" onClick={() => { pause(); prev(); start(); }}><AngleLeft width="24" height="24" fill="gray" /></CarouselButton>
<CarouselButton key="next" className="next" onClick={() => { pause(); next(); start(); }}><AngleRight width="24" height="24" fill="gray" /></CarouselButton>
<CarouselBox ref={carouselBoxRef} height={styleOption.height}>
<CarouselView>
<CarouselTrack contetWidth={boxSize} currentSlide={currentSlide}>
{Array.isArray(children)
? children.map((res, index) => <SlidePage key={`slidepage_${index}`} contetWidth={boxSize}>{res}</SlidePage>)
: children}
</CarouselTrack>
{banner ?? ''}
</CarouselView>
</CarouselBox>
</CarouselContainor>
</AppLayout>
)
}
export default Carousel
'nextjs' 카테고리의 다른 글
[error] next/image Un-configured Host (0) | 2023.07.10 |
---|---|
비동기 데이터로 jsx 구성 시 최적화 및 예외 처리 (0) | 2023.06.23 |
Next.js 에 <Link /> 는 무엇인가 (0) | 2023.04.06 |
Next.js getServerSideProps 에서 페이지 이동 방법 (0) | 2023.03.31 |
nextjs 기타 지원 기능 (0) | 2023.02.02 |