[캐러셀] 이미지슬라이더

youngseo·2022년 3월 4일
0

JS프로젝트

목록 보기
15/18

캐러셀(이미지슬라이더)

1. 캐러셀이란?

캐러셀은 유저가 스크롤을 내리지 않고도 볼 수 있는 정보의 양을 극대화하기 위해 사용하는 기법입니다.

이번에 구현을 해볼 캐러셀은 이미지 슬라이더로, 왼쪽 버튼을 클릭하면 왼쪽에서 슬라이드가 오른쪽버튼을 누르면 오른쪽에서 슬라이드가 등장하게금 구현을 해볼 예정입니다.

2.구성보기

HTML

활성화된 이미지에는 active 클래스가 이전 이미지에는 prev크래스가 다음 이미지에는 next클래스가 붙도록 하며 이미지 슬라이드를 구현해볼 예정입니다.

  <body>
    <div class="carousel-wrapper">
      <div class="carousel">
        <img class="carousel_item next" src="assets/1.jpeg" />
        <img class="carousel_item" src="assets/2.jpeg" />
        <img class="carousel_item" src="assets/3.jpeg" />
        <img class="carousel_item prev" src="assets/4.jpeg" />
        <img class="carousel_item active" src="assets/5.jpeg" /> 

        <div class="carousel_button--next"></div>
        <div class="carousel_button--prev"></div>
      </div>
    </div>

.carousel안에 모든 사용 요소가 들어있기 떄문에 class를 이용해 JS를 작성하는 것이 좋습니다.

css

추가적인 클래스가 붙지 않은 carousel_item의 경우 opacity:0transition효과를 받게끔 설정해놓았습니다.
active가 붙은 경우 opacity:1로 이미지를 노출시키고, next가 붙은 경우 transform: translateX(100%);을 통해 이미지가 우측에서 등장하게끔 구현해놓았습니다. 반대로 prev의 경우 transform: translateX(-100%);으로 왼쪽에서 등장하게끔 구현해놓았습니다.

.carousel-wrapper {
  overflow: hidden;
  width: 90%;
  margin: auto;
}

.carousel-wrapper * {
  box-sizing: border-box;
}

.carousel {
  -webkit-transform-style: preserve-3d;
  -moz-transform-style: preserve-3d;
  transform-style: preserve-3d;
}

.carousel_item {
  opacity: 0;
  position: absolute;
  top: 0;
  width: 100%;
  margin: auto;
  padding: 1rem 4rem;
  z-index: 100;
  transition: transform 0.5s, opacity 0.5s, z-index 0.5s;
}

.carousel_item.active {
  opacity: 1;
  position: relative;
  z-index: 900;
}

.carousel_item.prev,
.carousel_item.next {
  z-index: 800;
}

.carousel_item.prev {
  transform: translateX(-100%);
}

.carousel_item.next {
  transform: translateX(100%);
}

.carousel_button--prev,
.carousel_button--next {
  position: absolute;
  top: 50%;
  width: 3rem;
  height: 3rem;
  background-color: #fff;
  transform: translateY(-50%);
  border-radius: 50%;
  cursor: pointer;
  z-index: 1001;
  border: 1px solid black;
}

.carousel_button--prev {
  left: 0;
}

.carousel_button--next {
  right: 0;
}

.carousel_button--prev::after,
.carousel_button--next::after {
  content: ' ';
  position: absolute;
  width: 10px;
  height: 10px;
  top: 50%;
  left: 54%;
  border-right: 2px solid black;
  border-bottom: 2px solid black;
  transform: translate(-50%, -50%) rotate(135deg);
}

.carousel_button--next::after {
  left: 47%;
  transform: translate(-50%, -50%) rotate(-45deg);
}

js

;(function () {
  'use strict'

  const get = (target) => {
    return document.querySelector(target)
  }

  document.addEventListener('DOMContentLoaded', () => {
  })

})()

3. JS작성

;
(function () {
  'use strict'

  const get = (target) => {
    return document.querySelector(target)
  }

  class Carousel {
    constructor(carouselElement) {
      this.carouselElement = carouselElement;
      this.itemClassName = 'carousel_item';
      this.items = this.carouselElement.querySelectorAll('.carousel_item')

      this.totalItems = this.items.length
      this.current = 0
    }

    initCarousel() {
      this.items[0].classList.add('active')
      this.items[1].classList.add('next')
      this.items[this.totalItems-1].classList.add('prev')
    }

    setEventListener() {
      this.prevButton = this.carouselElement.querySelector('.carousel_button--prev')
      this.nextButton = this.carouselElement.querySelector('.carousel_button--next')
      this.prevButton.addEventListener('click', () => {
        this.movePrev()
      })
      this.nextButton.addEventListener('click', () => {
        this.moveNext()
      })
    }

    moveCarouselTo() {
      let prev = this.current - 1
      let next = this.current + 1

      if(this.current === 0) {
        prev = this.totalItems - 1
      } else if(this.current == this.totalItems - 1) {
        next = 0
      }

      for (let i = 0; i < this.totalItems; i++) {
        if(i === this.current) {
          this.items[i].className = this.itemClassName + ' active'//띄어쓰기 주의
        } else if ( i === prev ){
          this.items[i].className = this.itemClassName + ' prev'//띄어쓰기 주의
        } else if ( i === next) {
          this.items[i].className = this.itemClassName + ' next'//띄어쓰기 주의
        } else {
          this.items[i].className = this.itemClassName
        }
      }
    }

    moveNext() {
      if (this.current === this.totalItems - 1) {
        this.current = 0
      } else {
        this.current++
      }
      this.moveCarouselTo()
    }

    movePrev() {
      if(this.current === 0){
        this.current = this.totalItems - 1
      } else{
        this.current--
      }
      this.moveCarouselTo()
    }
  }

  document.addEventListener('DOMContentLoaded', () => {
    const carouselElement = get('.carousel')
    const carousel = new Carousel(carouselElement)

    carousel.initCarousel()
    carousel.setEventListener()
  })

})()

4. 클릭 시 delay를 통한 최적화

;
(function () {
  'use strict'

  const get = (target) => {
    return document.querySelector(target)
  }

  class Carousel {
    constructor(carouselElement) {
      this.carouselElement = carouselElement;
      this.itemClassName = 'carousel_item';
      this.items = this.carouselElement.querySelectorAll('.carousel_item')

      this.totalItems = this.items.length
      this.current = 0
      this.isMoving = false
    }

    initCarousel() {
      this.isMoving = false
      this.items[0].classList.add('active')
      this.items[1].classList.add('next')
      this.items[this.totalItems-1].classList.add('prev')
    }

    disabledInteraction() {
      this.isMoving = true
      setTimeout(() => {
        this.isMoving = false
      }, 500)
    }

    setEventListener() {
      this.prevButton = this.carouselElement.querySelector('.carousel_button--prev')
      this.nextButton = this.carouselElement.querySelector('.carousel_button--next')
      this.prevButton.addEventListener('click', () => {
        this.movePrev()
      })
      this.nextButton.addEventListener('click', () => {
        this.moveNext()
      })
    }

    moveCarouselTo() {
      if(this.isMoving) return
      this.disabledInteraction()
      let prev = this.current - 1
      let next = this.current + 1

      if(this.current === 0) {
        prev = this.totalItems - 1
      } else if(this.current == this.totalItems - 1) {
        next = 0
      }

      for (let i = 0; i < this.totalItems; i++) {
        if(i === this.current) {
          this.items[i].className = this.itemClassName + ' active'//띄어쓰기 주의
        } else if ( i === prev ){
          this.items[i].className = this.itemClassName + ' prev'//띄어쓰기 주의
        } else if ( i === next) {
          this.items[i].className = this.itemClassName + ' next'//띄어쓰기 주의
        } else {
          this.items[i].className = this.itemClassName
        }
      }
    }

    moveNext() {
      if(this.isMoving) return
      if (this.current === this.totalItems - 1) {
        this.current = 0
      } else {
        this.current++
      }
      this.moveCarouselTo()
    }

    movePrev() {
      if(this.isMoving) return
      if(this.current === 0){
        this.current = this.totalItems - 1
      } else{
        this.current--
      }
      this.moveCarouselTo()
    }
  }

  document.addEventListener('DOMContentLoaded', () => {
    const carouselElement = get('.carousel')
    const carousel = new Carousel(carouselElement)

    carousel.initCarousel()
    carousel.setEventListener()
  })

})()

0개의 댓글