프로그래머스 데브매칭 반응형 무한 캐러셀

창현·2021년 3월 2일
0
post-thumbnail

프로젝트 미리보기

반응형 무한 캐러셀 (모바일 이벤트 지원)

  • 모바일 이벤트 지원 추가
    • 스와이핑 모션 빠르기에 비례해 슬라이드 이동
    • 자동 재생 지원
    • 무한 캐러셀
  1. touch시 터치된 위치/시간 저장, autoplay일 경우 autoTimeout 삭제
  2. touch종료 시 터치된 지난 시간 , 이동한 위치, 속도를 이용해 대략적인 힘(force) 계산
  3. force에 비례해 넘길 슬라이드 개수(skips) 계산
  4. 개수만큼 슬라이드 이동 후, dx에 따라 슬라이드 방향 리셋
  5. autoplay 설정일 경우 autoplay 시작

  onTouchstart = (e) => {
    const { clientX, clientY } = e.touches[0]; 

    this.touchStart = e.timeStamp;
    this.touchPosition = { clientX, clientY };

    if (this.interval) {
      clearInterval(this.autoTimeout);
    }
  };

  onTouchEnd = (e) => {
    this.touchStartTimeout = console.log(e);
    const { clientX, clientY } = e.changedTouches[0];
    const timeStamp = e.timeStamp;

    const dx = clientX - this.touchPosition.clientX;
    const dy = clientY - this.touchPosition.clientY;
    const dt = timeStamp - this.touchStart;

    if (dx === 0) return;

    const distance = Math.sqrt(dx ** 2 + dy ** 2);
    const velocity = distance / dt;
    const k = 10;

    const force = velocity ** 2 * k;

    let skips = Math.floor(Math.sqrt(force)) || 1;

    while (skips) {
      dx > 0 ? this.prevSlide() : this.nextSlide();

      skips--;
    }

    this.direction = dx > 0 ? 'prev' : 'next';

    if (this.interval) {
      this.autoPlay();
    }
  };

모달 UI 분리

  1. 백드랍
import Component from '../components/Component.js';

export default class Backdrop extends Component {
  constructor(target, attributes) {
    super(target, 'div', {
      ...attributes,
      className: 'Backdrop' + (attributes.className || ''),
      styles: {
        backgroundColor: 'rgba(0, 0, 0, 0.5)',
        position: 'fixed',
        zIndex: 2000,
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        ...attributes.styles,
      },
    });
  }
}
  1. 모달
import Component from '../components/Component.js';
import Backdrop from './Backdrop.js';

export default class Modal extends Backdrop {
  constructor(target, content, attributes) {
    super(target, {
      ...attributes,
      className: 'Modal ' + (attributes.className || ''),
      styles: {
        ...attributes.styles,
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
      },
    });

    // HTML template일 경우
    if (typeof content === 'string') {
      this.addHTML(this.$, content);
    // 컴포넌트일 경우 (아직 확인 x)
    } else if (typeof content === 'function') {
      this.$content = new content(this.$);
    }

    this.bindEvents();
  }

  render() {
    this.$content && this.$content.render && this.$content.render();
  }
}
  1. 모달 사용하기
import Component from './Component.js';
import Modal from '../UI/Modal.js';

export default class CatInfoModal extends Modal {
  constructor($parent, data) { 
    const { url, name, temperament, origin } = data;

    super(// $parent, content, attributes
      $parent,
      `<div class="content-wrapper pd-5 card"> 
        <div class="title mb-3">
          <span>${name}</span>
          <div class="close btn">x</div>
        </div>
        <div class="img-wrapper mb-3">
          <img src="${url}" alt="${name}"/>        
        </div>
        <div class="description">
          <div>성격: ${temperament}</div>
          <div>태생: ${origin}</div>
        </div>
      </div>`,
      {
        className: 'CatInfoModal',
        tabIndex: 0,
        styles: {
          transition: 'opacity 300ms',
          opacity: 0,
        },
      }
    );

    this.$.focus();
    this.$.classList.add('fade-in');

    this.data = data;
    this.bindEvents();
  }

  removeWithFadeOut = () => {
    this.$.classList.remove('fade-in');
    this.$.classList.add('fade-out');
    this.$.ontransitionend = () => this.$.remove();
  };

  onClick = (e) => {
    if (e.target === this.$.querySelector('.close') || e.target === this.$) {
      this.removeWithFadeOut();
    }
  };

  onKeyDown = (e) => {
    e.key === 'Escape' && this.removeWithFadeOut();
  };
}
profile
띵가띵가

0개의 댓글