라이브러리 없이 이미지 슬라이드 구현하기

Miog Yang·2022년 9월 15일
0

Project

목록 보기
2/7

👉 다시 만들어보는 이미지 슬라이드


👉 슬라이드 데모영상

필요한 라이브러리

npm install react-icon

💡 버튼은 아이콘을 받아서 작업하였다. 이미지로 작업을 하거나 특수문자를 사용해도 된다.



필요한 컴포넌트

  • Slide.js : 이미지 슬라이드 전체를 감싸는 컴포넌트
  • Button.js : 슬라이드의 prev, next의 기능을 구현할 버튼
  • dataSlider.js : 이미지 데이터 생성
  1. 이미지는 public폴더에 images라는 폴더에 담는다.
  2. dataSlider.js 파일에 img들을 담을 객체를 슬라이드 이미지 갯수만큼 생성한다.
>>>> dataSlider.js


const dataSlider = [
  {
    id: 0,              // id를 key값으로 사용 0 ~ 이미지갯수
    title: "",
    text: ""
  },
  {
    id: 1,
    title: "",
    text: ""
  },
  
  ...
   
]
export default dataSlider;

💡 이미지를 map으로 돌릴때 key값이 필요하다.
이미지 안에 넣을 title이나 text는 사용여부에 따라 사용하면 된다.
이미지 폴더안에 사진들의 이름은 하나의 이름으로 통일하되 뒤에 숫자로 구별한다.
📌 refer : 리액트 key



슬라이드 작업시작!

1. Slide.js생성

1) import와 레이아웃

  • 큰 틀 만들기

👉 import

  • dataSlider : 이미지 슬라이드에 담을 데이터
  • Button 컴포넌트 : 버튼은 아이콘을 사용하고 기능 함수를 props로 넘겨줌
  • useEffect,useState : 상태값을 저장 useState, 무한슬라이드 useEffect
  • sass파일
>>>> Slide.js

return (
    <div className="slide-container"> //컨테이너
      <div className="slide">         //map으로 데이터를 받을 슬라이드
          <img 
  		  className="slide-img"
          src="이미지경로"/>            //img폴더에서 파일을 받는 부분
          <span className="slide-title">
  			이미지 title              //받은 데이터에서 title이 들어가는 부분
  		  </span> 
       </div>
      
      <Button /> //next버튼
      <Button /> //prev버튼
  
      <div className="slide-dot"> //슬라이드 기능과 함께 넘어가는 도트부분
  	  </div>
      
      </div>
    </div>
  )
  • 이미지 넣어주기

 {dataSlider.map((slide, index)=>{	
   return <div key={slide.id} 		//key값은 id
   			className="slide">
     		<img className="slide-img"
          	src={process.env.PUBLIC_URL + `/imgs/img${index +1}.jpg`} alt="mainImg"/> 
          	<span className="slide-title">{slide.title}</span>
          </div>
      })}

📌 refer : public폴더에서 가져오는 이미지 경로설정

💡 index로 이미지를 불러오는데 index는 0부터 시작이므로 +1을 적용해준다.

2) div.slide-container > div.slide > div.slide-img 순으로 태그생성 후 스타일 적용

  • .slide-container : 이미지 슬라이드를 감싸는 컨테이너
    슬라이드의 화면크기와 position을 지정해주고 지정된 사이즈 안에서만 이미지가
    보일수 있도록 overflow를 지정해준다.
  • .slide : img태그를 감싼다. map을 적용할 태그 img src에 이미지 파일생성
  • .slide-img : 이미지 사이즈 100%, object-fit적용
    📌 refer : object-fit

💡 컨테이너는 화면에 보여지는 사이즈와 img가 나열되면 화면을 벗어나기때문에 보여지는
화면외에 안보이게 overflow:hidden, 이미지 묶음이 컨테이너 안으로 들어와야 하므로 position을 relative로 지정해줘야한다.
태그에 적용될 데이터를 글이나 사진을 미리 넣어서 레이아웃을 잡아보자!
그래도 어렵다면 👇


>>>> Slide.scss

.slide-container{
  width: 90%;			//화면이 브라우저에서 90%만 보이게 적용
  height: 600px;
  margin: 0 auto;
  position: relative;
  overflow: hidden;
  .slide{
    width: 100%;
    position: absolute;
    top: 0; left: 0;
    opacity: 0; //슬라이드 구현시 삼항연산자에 사용될 스타일값 : "active-animation"가 적용될 때 0
    transition: opacity ease-in-out 0.4s; //이미지가 넘어갈때 적용될 animation효과
    .slide-img{				//실제 이미지에 적용될 스타일
      width: 100%;
      height: 100%;
      object-fit: cover;	//refer확인
    }
    .slide-title{			//이미지에 적용될 title스타일
      position: absolute;
      top: 250px; left: 25%;
      font-size: 80px;
      font-weight: 600;
      color: #fff;
      z-index: 200;
    }
  }
  .active-animation{ //슬라이드 구현시 삼항연산자에 사용될 스타일값
    opacity: 1;
  }

💡 슬라이드 구현은 이미지가 적용되는 태그의 className에 삼항연산자를 이용하여 적용한다.

2. slide기능 구현

1) 슬라이드 현재 상태값 => img태그에 경로 지정

2) Button 함수생성 => Button 컴포넌트 생성후 담기

<>>>> Slide.js

const [slideIndex,setSlideIndex] = useState(1); //슬라이드 현재상태값

		...

	<img 
	 className={slideIndex === index + 1 ? "slide active-animation" : "slide"}
     src={process.env.PUBLIC_URL + `/imgs/img${index +1}.jpg`} alt="mainImg"/> 

		...


>>>> Button컴포넌트에 함수적용

 const nextSlide = ()=>{}  //next 버튼에 사용할 함수
 const prevSlide = ()=>{}  //prev 버튼에 사용할 함수
  
 		...

  	 <Button 
    	moveSlide={nextSlide}
  		direction={"next"}/> //next버튼에 아이콘 적용부분에서 사용할 방향값
     <Button 
		moveSlide={prevSlide}
		direction={"next"}/> //prev버튼에 아이콘 적용부분에서 사용할 방향값

 		...

3) Button컴포넌트 생성 후 스타일 적용

👉import

  • react-icon : react에서 사용할 아이콘을 가져온다.
    📌 refer : react-icon
  • Slide.scss : Slide.js와 Button.js를 하나로 넣어줬으며 그대로 가져온다.
>>>> Button.js 


import {IoIosArrowBack,IoIosArrowForward} from 'react-icons/io'; //사용할 icon을 불러오기
import './Slide.scss'; //스타일

function Button({moveSlide, direction}){ //함수와 방향값을 담은 이름으로 가져온다.
 //console.log(moveSlide, direction) //콘솔확인 : 함수와 방향값
 return(
     <button 
     onClick={moveSlide} //onClick이벤트에 함수를 담는다.
     className={direction === "next" ? "next" : "prev"}
     >{direction === "next" ? <IoIosArrowForward /> : <IoIosArrowBack />}
	 </button>
 )
}
export default Button;
  • onClick에 넣어줄 moveSlide함수
>> next 버튼

const nextSlide = ()=>{
    if(slideIndex !== dataSlider.length){
      setSlideIndex(slideIndex +1)
    }else if(slideIndex === dataSlider.length){
      setSlideIndex(1)
    }
  }
  
>> prev 버튼

  const prevSlide = ()=>{
    if(slideIndex !== 1){
      setSlideIndex(slideIndex -1)
    }else if(slideIndex === 1 ){
      setSlideIndex(dataSlider.length)
    }
  }

💡next 버튼
: 현재 이미지 index가 이미지의 마지막 index와 다를 경우 이미지 index에 +1이되고
현재 이미지 index가 이미지의 마지막 index와 같을 경우 초기값으로 적용된다.
💡prev 버튼
: 현재 이미지 index가 이미지의 index초기값과 다를 경우 이미지 index에 -1이되고
현재 이미지 index가 이미지의 index초기값과 같을 경우 마지막 index로 적용된다.

💡 리액트 아이콘 사용하기
1. 사용할 아이콘을 import에 담는다.
2. 아이콘이름에 앞에 두글자를 react-icon에 담는다.
ex)IoIosArrowBack => io => from 'react-icons/io'
3. 사용할 태그에 컴포넌트처럼 넣어준다.

  • Button컴포넌트 스타일
>>>> style

.next{    
    font-size: 80px;    //icon size
    padding-left: 30%;	//padding값으로 버튼주변에 여백을 주어 hover적용에 사용함
    padding-top: 15%;
    padding-bottom: 10%;
    position: absolute; //슬라이드 컨테이너 안으로 넣어준다.
    top: 0; right: 5%;  //absolute적용시 위치는 필수로 지정해줘야 한다.
    z-index: 100;		//이미지 위로 올려야 하므로 적당히 100으로 올려준다.
    background-color: rgba($color: #333, $alpha: 0); //hover에 적용될 여백은 보이지 않아야 하므로 alpha: 0으로 적용
    border: none;		//버튼태그에 구현되는 보더 삭제
    opacity: 0;			//hover시 버튼이 보여야 하므로 기본 0으로 지정
  }
  &:hover .next{
    opacity: 0.7;		//hover효과
  }

💡 next와 prev의 스타일 적용은 전체적으로 같으나 absolute에서 위치 지정시 left와 right로 적용




3. Dot 설정

  • dot가 들어갈 태그의 클릭이벤트에 적용할 함수를 설정하고 dot에 변경값을 넣어줌
>>>> Slide.js

const moveDot = index =>{  //Dot함수 설정
    setSlideIndex(index)
  }

		...
        
<div className="slide-dot">
        {Array.from({length:6}).map((img, index)=>(
          <div 
          onClick={()=> moveDot(index + 1)}
          className={slideIndex === index +1 ? "dot active" : "dot"}></div>
        ))}
      </div>

💡Array.from : 반복되는 객체를 받아서 새로운 객체를 만든다.
=> lenth 6개를 객체로 생성 후 받아서 div로 생성.


  • style
    .slide-dot: 전체 레이아웃
    .dot : dot스타일
    .active : 현재 이미지의 위치
>>>> style

.slide-dot{
    position: absolute;
    bottom: 50px; right: 10%;
    display: flex;
    z-index: 100;  
    .dot{
      width: 15px; height: 15px;
      margin: 5px;
      background-color: rgba($color: #333, $alpha: 0.8);
    }
    .active{
      width: 15px; height: 15px;
      margin: 5px;
      border: 2px solid #fff;
      background-color: rgba($color: #fff, $alpha: 0.2);
    }
  }



4. useEffect 무한 슬라이드


>>>> Slide.js

useEffect (()=>{
    const intervar = setInterval(()=>{
      setSlideIndex(slideIndex !== dataSlider.length
        ? slideIndex +1 
        : 1);	//현재 이미지와 이미지갯수가 다르면 이미지 +1 같으면 이미지 1
    },3000);	//3초마다 슬라이드
    return () => clearInterval(intervar);
  },[slideIndex])

📌 refer : setInterval(콜백함수,시간)과 clearInterval




✏️ 이미지 슬라이드를 마치며

프로젝트 작업하면서 라이브러리없이 슬라이드 구현을 검색하는데 생각보다 정보가 많지 않았다.
리액트는 라이브러리를 사용하려고 쓰는구나 싶을 정도..
이미지 슬라이드를 다시 구현하면서 예전에는 메인컴포넌트에 이미지 데이터를 전부 넣어서
사용했는데 이번에는 public폴더에 있는 이미지를 process.env.PUBLIC_URL로 가져오고
slide, slideContent, button, dot 전부 컴포넌트화해서 작업했던 예전과 달리
필요한 세가지 slide,button만 컴포넌트화 하고 dot는 바로 만들어서 더 깔끔하게 작업할수 있는 계기가 되었다.
한번 구현했다고 끝난것이 아닌 또 다른 방법을 학습하는 필요성을 느낀 작업이였다.

점점 더 깔끔한 나의 코드를 위해!!

profile
주니어 개발사전 & 프론트엔드 도전기

0개의 댓글