JavaScript

[나의 toy 프로젝트] - 직접 Carousel 만들기

건강한_개발자 2023. 6. 12. 15:54

 

 

기본 code 세팅

<index.html>

<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover" />
  <title>carousel</title>
  <link rel="stylesheet" href="../../utils/reset.css" />
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <div class="carousel-wrapper">
    <div class="carousel">
      <img class="carousel_item" src="assets/0.jpg" height="400px" />
      <img class="carousel_item" src="assets/4.jpg" height="400px" />
      <img class="carousel_item" src="assets/c.jpg" height="400px" />
      <img class="carousel_item" src="assets/3.jpg" height="400px" />
      <img class="carousel_item" src="assets/5.jpeg" height="400px" />

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

  <script src="script.js"></script>
</body>

</html>

 

<style.css>

.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);
}

기타 img파일들을 가져와서 asser 폴더에 넣어준다.

 

<폴더 구성>

 

 



시작. 

 

class Carousel {
    constructor(carouselElement) {
      this.carouselElement = carouselElement
    }
  }

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

<code1>

  1. Carousel 클래스를 만든다.
  2. carousel 인스턴스를 만들고 매개변수로 carouselElement 를 넣어준다.
    • carouselElement → DOM 문서의 클래스가 carousel인 element)
  3. this.carouselElement = carouselElement → carousel div가 carouselElement 에 할당된다.

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

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

<code2>

  1. this.items = this.carouselElement.querySelectorAll('.carousel_item')
    1. querySelectorAll로 클래스명인 carousel_item들을 모두 가져와 items에 담는다.
  2. this.totalItems = this.items.length //5
    1. items의 총 개수를 의미
  3. this.current = 0
    1. 처음 캐러셀 아이템을 0으로 잡아준 것이다.

 

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()
      })
    }

<code3>

setEventListener() 함수 작성

 


 

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()
    }

<code4>

moveNext() 작성 → next버튼 클릭시

movePrev() 작성 → prev 버튼 클릭시

 

 


 

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
      }
    }

<code5>

moveCarouselTo() 작성

  1. prev , next 구하기
  2. 예외처리하기
    1. 현재 current가 0인경우, → prev = this.totalItems - 1
    2. 현재 cruuent가 4번쨰인경우,→ next = 0
    3. → this.current === this.totalItems - 1

 

 


 

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
        }
      }
    }

<code6> → 클래스 붙여주기 작업

  1. i === this.current → i가 현재 current인 경우,
  2. i === prev → i가 prev인 경우
  3. i === next → i가 next인 경우
  4. 그 외의 경우

 


 

//캐러셀 초기화 메서드
initCarousel() {
    this.items[0].classList.add('active')
    this.items[1].classList.add('next')
    this.items[this.totalItems - 1].classList.add('prev')
    }

<code7> 캐러셀 초기화해주는 메서드작성 → initCarousel()

 


 

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

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

<code8> 마무리

carousel.initCarousel()

  1. carousel 인스턴스를만들기 (이미전에 만들어놈)
  2. initCarousel() 실행시키기
  3. carousel.setEventListener() 실행시키기
    1. setEventListener는 이벤트 리스터를 각 버튼에다가 지정해주는 메서드이다. (위 코드를 살펴보자)

 


잘 동작하는지 체크

 

<초기상태>

 

<초기상태 -> next 버튼 클릭시> 

 

<초기상태 -> prev 버튼 클릭시>

 

 

이상으로 캐러셀은 정상 동작한다.

굳이 문제점을 찾자면,. 계속 클릭시, 계속 이벤트가 발생한다는 문제점이 있다.

클릭시  딜레이를 줘서 최적화 하는 작업을 진행이 필요하다.

 

전체 javascript 코드 

;(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 //5
      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()
  })
})()