Carousel
캐러셀 슬라이더는 일반적으로 이미지를 옆으로 넘기며 정보를 확인할 수 있는 방식이며,
많은 웹페이지에서 더 나은 사용자 경험을 위하여 자주 사용된다.
라이브러리를 사용하면 보다 쉽게 구현이 가능하지만 vanilla JavaScript로도 충분히 가능하다.
이번에는 React hooks의 useState, useEffect, useRef와 styled components로 무한반복 슬라이드를 구현해보려고 한다.
setting
npx create-react-app react-carousel
npm install --save styled-components
Slide component
Carousel component의 요소가 되는 slider component를 만든다.
import React from "react";
import styled from "styled-components";
export default function Slide({ src, alt }) {
return <IMG src={src} alt={alt} />;
}
const IMG = styled.img`
margin: 0 10px;
border-radius: 10px;
height: 300px;
width: 100%;
`;
Carousel에서 Slider 컴포넌트를 가져와서 map을 돌리고 url을 props로 넘겨준다.
// Carousel.js
{ImgData.map((item) => {
return <Slide src={item.src} alt={item.alt} />;
})}
// img url
const ImgData = [
{
id: 1,
src: "https://static.wanted.co.kr/images/banners/1473/41f7b36e.jpg",
alt: "개발자 되고싶은 분들!?",
},
...
Carousel component
Slide를 담을 <SlideConatainer>와 전체 큰 틀 <Container>를 만들었다.
export default function Carousel() {
return (
<Container>
<SlideContainer ref={slideRef}>
{ImgData.map((item) => {
return <Slide src={item.src} alt={item.alt} />;
})}
</SlideContainer>
<BtnL onClick={PrevSlide}>왼</BtnL>
<BtnR onClick={NextSlide}>오</BtnR>
</Container>
);
}
const Container = styled.div`
margin: 75px auto;
width: 100%;
/* overflow: hidden; */
`;
const SlideContainer = styled.div`
display: flex;
margin: 0 auto;
width: 1080px;
`;
이미지를 한장씩만 보여줄 거라면 flex로 이미지를 가로로 나열하고 overflow:hidden으로 컨테이너 넘어간 이미지 보이지않게 설정한다.
const TotalSlides = 8; //전체슬라이드개수
const [currentSlide, setCurrentSlide] = useState(0); //현재슬라이드
const slideRef = useRef(null);
const NextSlide = () => { //다음버튼을 누를 때
if (currentSlide >= TotalSlides) { //마지막 슬라이드라면 처음으로 돌아간다
setCurrentSlide(0);
} else {
setCurrentSlide(currentSlide + 1);
}
};
const PrevSlide = () => {
if (currentSlide === 0) {
setCurrentSlide(TotalSlides);
} else {
setCurrentSlide(currentSlide - 1);
}
};
전체 슬라이드 개수를 지정한다. 단, 배열처럼 0부터 시작했으므로 총9장이면 8로 지정한다.
다음버튼과 이전버튼을 눌렀을 때의 슬라이드효과를 if문으로 설정해준다.
nextslide는 마지막 슬라이드면 처음슬라이드로 넘어가고 아니라면 그다음 +1의 슬라이드를 보여주게 설정한다.
useEffect(() => {
slideRef.current.style.transition = "transform .5 ease-in-out";
slideRef.current.style.transform = `translateX(-${currentSlide}00%)`;
}, [currentSlide]);
useEffect로 현재 어느 슬라이드를 보여주고 있는지를 지정한다.
가로로 slide들이 나열되어 있으므로 translateX로 양옆으로 이미지의 위치를 조정한다.
🔻 transition
: 화면이동(transition)은 어떠한 변형(transform)이 일어나는 동안의 상태를 말한다.
시감함수를 이용한 가속도 처리 (화면전환의 효과 / transition-timing-function)
linear : 등속도, 전환과정에 속도의 변화없이 처음부터 끝까지 흐름 일정하게 유지
ease : 점진적 가속
ease-in : 가속
ease-out : 감속
ease-in-out : 점진적 가속 후에 감속
Carousel 첫슬라이드-마지막슬라이드 연결
구현하고자하는 캐러셀은 해당 슬라이드만 보여지는게 아니라 앞-뒤의 슬라이드의 일부분도 보여지는 캐러셀이라
1번 슬라이드가 보일시에 마지막 슬라이드가 보여지지않는 문제가 생겼다.
해결하기 위하여 이미지url이 있는데이터에 앞뒤로 마지막과 첫슬라이드를 추가해주었다
기존 ( 1 - 2 - 3 -...- 7 - 8 - 9 )
변경 ( 9 - 1 - 2 - 3 -...- 7 - 8 - 9 - 1 )
그리고 버튼이벤트의 if문을 추가로 수정
//const TotalSlides = 8; //전체슬라이드개수
const TotalSlides = 9;
//const [currentSlide, setCurrentSlide] = useState(0); //현재슬라이드
const [currentSlide, setCurrentSlide] = useState(1);
const NextSlide = () => {
if (currentSlide >= TotalSlides) {
//setCurrentSlide(0);
setCurrentSlide(1);
} else {
setCurrentSlide(currentSlide + 1);
}
};
const PrevSlide = () => {
//if (currentSlide === 0) {
if (currentSlide === 1) {
setCurrentSlide(TotalSlides);
} else {
setCurrentSlide(currentSlide - 1);
}
};
[해결]
[ 추가 ]
첫번째- 마지막 슬라이드 구간에서 매끄럽지않은 부분이 있어서 앞뒤로 슬라이드 2개씩을 더 추가했다.
export default function Carousel() {
const TotalSlides = 10;
const [currentSlide, setCurrentSlide] = useState(2);
const slideRef = useRef(null);
const Refstyle = slideRef.current;
const NextSlide = () => {
if (currentSlide >= TotalSlides) {
Refstyle.style.transition = `none`;
Refstyle.style.transform = `translateX(-100%)`;
setCurrentSlide(2);
} else {
setCurrentSlide(currentSlide + 1);
}
};
const PrevSlide = () => {
if (currentSlide === 1) {
Refstyle.style.transition = `none`;
Refstyle.style.transform = `translateX(-1000%)`;
setCurrentSlide(9);
} else {
setCurrentSlide(currentSlide - 1);
}
};
useEffect(() => {
slideRef.current.style.transition = "transform .3s ease-in-out";
slideRef.current.style.transform = `translateX(-${currentSlide}00%)`;
}, [currentSlide]);
✔️ 추가로 해결해야될 사항
- carousel auto move + button click event 충돌문제
- 반응형에서 현재 slider 중앙 위치시키기
'Archive' 카테고리의 다른 글
[TIL220125] JSON (0) | 2022.01.26 |
---|---|
[React] 환율계산기 (0) | 2022.01.26 |
[TS] keyof / Mapped Types / infer 등 (0) | 2022.01.17 |
[TS] declare / d.ts / index signatures (0) | 2022.01.13 |
[TS] React (0) | 2022.01.12 |