Image Slider

yoon Y·2022년 2월 10일
0

Vanilla Project

목록 보기
6/13

ImageSlider 래퍼런스

구현 방법

초기 로직 세팅

  • 각 슬라이드는 li에 해당한다
  • maxLength는 슬라이드 이미지의 총 갯수
  • state에 (슬라이드 이미지의) 초기 index(1)를 설정한다.
  • prev, next버튼에 이벤트를 걸어주는데 prev는 state-1, next는 state+1을 해준다
  • 상태+1이 maxLength보다 크면 0으로, 상태-1이 0보다 작으면 maxLength를 할당해준다 (0~maxLength 범위를 순환하도록)

이벤트가 발생하면 (prev 또는 next버튼 클릭)

  • curretState번째 li를 display:none으로 변경한다
  • 상태를 바꿔준다(+1, 또는 -1)
  • nextState번째 li를 display: block으로 변경한다

코드

class ImageSlider extends Component<PropsType> {
  state: number;
  maxLength: number;
  constructor($target: Element, props: PropsType) {
    super($target, props);
    this.state = 1;
    this.maxLength = this.props.imageUrlList.length;
    this.render();
    this.activeSlide(true);
  }

  setState(nextState: number) {
    if (nextState > this.maxLength) {
      this.state = 1;
      return;
    }
    if (nextState < 1) {
      this.state = this.maxLength;
      return;
    }
    this.state = nextState;
  }

  template(): string {
    return `
    <div class='Image-slider-container'>
      <div class='image-slider'>
        <ul class='slider-list'>
          ${this.props.imageUrlList
            .map(url => `<li class='slider-item fade '><img src="${url}"></li>`)
            .join('')}
        </ul>
        <button class='prev'>❮</button>
        <button class='next'>❯</button>
      </div>
      <div class='dots'>
      ${this.props.imageUrlList
        .map((_, i) => `<span class='dot dot_${i}'></span>`)
        .join('')}
      </div>
    </div>
    `;
  }

  _setCurrentItemBlock(param: boolean) {
    const currentItem = document.querySelector(
      `.slider-item:nth-child(${this.state})`,
    );
    if (currentItem instanceof HTMLElement) {
      currentItem.style.display = param ? 'block' : 'none';
    }
  }

  _setCurrentDotOn(param: boolean) {
    const currentDot = document.querySelector(`.dot_${this.state - 1}`);

    if (currentDot instanceof HTMLElement) {
      currentDot.style.backgroundColor = param ? '#717171' : '#bbb';
    }
  }

  activeSlide(param: boolean) {
    this._setCurrentItemBlock(param);
    this._setCurrentDotOn(param);
  }

  handleClickButton(status: string) {
    this.activeSlide(false);
    this.setState(status === 'prev' ? this.state - 1 : this.state + 1);
    this.activeSlide(true);
  }

  mount() {
    const prevButton = document.querySelector('.prev');
    const nextButton = document.querySelector('.next');

    prevButton?.addEventListener('click', () => {
      this.handleClickButton('prev');
    });
    nextButton?.addEventListener('click', () => {
      this.handleClickButton('next');
    });
  }

  render() {
    this.$target.innerHTML = '';
    this.$target.innerHTML = this.template();
    this.mount();
  }
}
export default ImageSlider;
profile
#프론트엔드

0개의 댓글