Archive

[React] Carousel 구현

manon_e 2022. 1. 18. 15:35
반응형

 

 

 

     


     

    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