[React] 이미지 슬라이드 구현

23954 단어 ReactReact

위코드 1차 프로젝트로 캉골 클론 프로젝트 진행중에 있습니다.

상품상세 페이지 클론 중 상품이미지 슬라이드를 라이브러리 없이 구현한 방법에 대해 정리해 보고자 합니다.

✏️ 하고 싶은 것

  • 메인 이미지 : 현재 이미지를 큰 영역으로 표시
  • 페이지 페이지네이션 : 현재 이미지 / 전체 이미지 수
  • 이미지 섬네일 : 표시할 이미지를 메인 이미지 영역 아래 섬네일 형식으로 표시. 이미지 최대 갯수는 4개로 설정
  • 이전, 다음 버튼 : 메인 이미지 마우스오버 시 버튼이 표시되며, 버튼 클릭 시 메인 이미지가 이전, 다음 이미지로 전환.

동작 화면


(화면 녹화를 처음해 보았는데.. 특정영역만 녹화하는 방법을 모르겠더라구요 😭)

구현 방법

  • 이미지 wrapper 너비를 고정시켜 두고, 이미지를 일렬로 배치 시켜 둡니다.
  • wrapper의 너비 외 영역은 보이지 않도록 overflow-x: hidden;으로 처리합니다.
  • 이미지 이동 시 css의transform: translate3d(이미지 너비px, 0px, 0px) 속성을 사용하여 배경 이미지 위치를 변경합니다.
  • 참고 : https://im-developer.tistory.com/97

js

import React from 'react';
import './ImageSlide.scss';

class ImageSlide extends React.Component {
  constructor() {
    super();
    this.state = {
      imageCurrentNo: 0,
    };
  }

  onChangeImage = index => {
    if (this.props.images.length <= index) index = 0;
    if (index < 0) index = this.props.images.length - 1;

    this.setState({ imageCurrentNo: index });
  };

  render() {
    const { images } = this.props;
    return (
      <div className="imageSlide">
        <div className="navBox">
          <span>{this.state.imageCurrentNo + 1}</span>
          <span>/</span>
          <span>{images && images.length}</span>
        </div>
        <div className="slideBox">
          <div
            className="slideList"
            style={{
              transform: `translate3d(
                ${this.state.imageCurrentNo * -500}px, 0px, 0px`,
            }}
          >
            {images?.map((image, no) => (
              <div className="slideContent" key={no}>
                <picture>
                  <img src={image} />
                </picture>
              </div>
            ))}
          </div>

          <div
            className="buttonPrev"
            onClick={() => this.onChangeImage(this.state.imageCurrentNo - 1)}
          >
            <i class="fas fa-chevron-left"></i>
          </div>
          <div
            className="buttonNext"
            onClick={() => this.onChangeImage(this.state.imageCurrentNo + 1)}
          >
            <i class="fas fa-chevron-right"></i>
          </div>
        </div>
        <div className="paginationBox">
          {images?.map((image, no) => (
            <div
              key={no}
              onClick={() => {
                this.onChangeImage(no);
              }}
            >
              <picture>
                <img src={image} />
              </picture>
            </div>
          ))}
        </div>
      </div>
    );
  }
}

export default ImageSlide;

scss

.imageSlide {
  position: relative;
  width: 500px;
  margin: auto;
  padding-bottom: 30px;

  .navBox {
    position: absolute;
    top: 20px;
    left: 20px;
    font-size: 14px;
    z-index: 2;

    span {
      padding: 0 5px;
    }
  }

  .slideBox {
    position: relative;
    width: 100%;
    margin: auto;
    overflow-x: hidden;

    .slideList {
      width: 2800px;
      transition: all 300ms ease 0s;
      overflow: hidden;

      .slideContent {
        display: table;
        float: left;
        width: 500px;
        height: 500px;

        picture {
          display: table-cell;
          vertical-align: middle;
          text-align: center;

          img {
            width: 100%;
            height: auto;
          }
        }
      }
    }

    &:hover .buttonPrev {
      left: 0;
      transition: left 0.5s;
    }

    &:hover .buttonNext {
      right: 0;
      transition: right 0.5s;
    }

    .buttonPrev,
    .buttonNext {
      position: absolute;
      top: 225px;
      width: 50px;
      height: 50px;
      padding-top: 5px;
      background-color: #333;
      font-size: 40px;
      font-weight: 100;
      vertical-align: middle;
      color: #eeeeee;
    }
    .buttonPrev {
      left: -50px;
    }
    .buttonNext {
      right: -50px;
    }
  }

  .paginationBox {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    width: 100%;
    grid-column-gap: 3px;

    picture {
      width: 100%;

      img {
        width: 100%;
        cursor: pointer;
      }
    }
  }
}

좋은 웹페이지 즐겨찾기