30개의 프로젝트로 배우는 프론트엔드 with VanillaJS (2-1) 이미지슬라이더

productuidev·2022년 8월 16일
0

FE Study

목록 보기
49/67
post-thumbnail
post-custom-banner

[fastcampus] 30개의 프로젝트로 배우는 프론트엔드 with VanillaJS (2-1)

(2) 바닐라 자바스크립트로 만드는 이미지 슬라이더

jQuery 라이브러리를 사용하지 않고 만드는 슬라이더

프로젝트 개요

  • image slide, next/prev, indicator 기능 구현
  • setTimeout, setInterval에 대해 이해
  • autoplay/stop 기능 구현

개발 환경 설정

  • webpack-boilerplate (강사 GitHub에서 clone)
  • eslint-config-airbnb
  • prettier rules
{
  "trailingComma": "all", 
  "bracketSpacing": true,
  "useTabs": false,
  "semi": true, 
  "printWidth": 80,
  "arrowParens": "avoid", 
  "proseWrap": "never", 
  "endOfLine": "auto",
  "tabWidth": 2, 
  "singleQuote": true
 }

Static Resources

1) 제공된 html, css, images 추가
2) Icon
Font Awesome에서 슬라이더에 사용할 Free Icon<i> 찾기

      <div class="btn next" id="next">
        <i class="fa fa-arrow-right"></i>
      </div>
      <div class="btn previous" id="previous">
        <i class="fa fa-arrow-left"></i>
      </div>
      
      <div class="control-wrap play" id="control-wrap">
        <i class="fa fa-pause" id="pause" data-status="pause"></i>
        <i class="fa fa-play" id="play" data-status="play"></i>
      </div>

npm install --save @fortawesome/fontawesome-free

package.json

  "dependencies": {
    "@fortawesome/fontawesome-free": "^6.1.2"
  }
  • src/css/style.css에 설치된 fontawesome import 시키기
    (node_modules > @fortawesome > font/awesome-free > css > all.min.css)

src/css/style.css

@import url('~@fortawesome\fontawesome-free\css\all.min.css');

3) image 관련 설정 변경

webpack.config.js

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /\,jpeg$/,
        type: 'asset/inline', //image는 webpack에 있는 내장 loader로 읽어들이겠다
      }
    ],
  },

4) html에서 image 관련 마크업을 lodash 문법으로 변경

<%= require('이미지 경로') %>

      <ul class="list slider" id="slider">
        <li>
          <img src="<%= require('./src/image/red.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/orange.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/yellow.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/green.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/blue.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/indigo.jpeg') %>" />
        </li>
        <li>
          <img src="<%= require('./src/image/violet.jpeg') %>" />
        </li>
      </ul>

기타 : npm run dev 실행 시 css eslint(rules prettier) 에러 해결

.eslintrc.json

  "rules": {
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "parser": "flow"
      }
    ]
  }
  • 제공된 index.html : 전체 마크업 구조 파악

  • 제공된 css : 전체 스타일링 구조 파악
.slider-wrap { ... }

/* ! 총 슬라이드 이미지는 8개이며, left: -1000px 값을 줘서 슬라이드 이미지 다음장으로 변경되도록 */
.slider-wrap ul.slider {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0px;
}
/* ! */
.slider-wrap ul.slider li {
  float: left;
  width: 1000px;
  height: 400px;
}

/* ! 버튼 부분 위치/hover했을 때 효과 */
.btn { ... }
.btn:hover { ... }
.next { ... }
.previous { ... }

/* ! 인디케이터는 슬라이더 갯수를 세서 li 개수가 자동생성될 예정 */
.indicator-wrap { … }
.indicator-wrap ul { ... }
.indicator-wrap ul li { ... }
.indicator-wrap ul li.active { ... }
.slider-wrap ul { ... }
.control-wrap { ... }
.control-wrap i { ... }

/* ! 재생/멈춤 */
.play .fa-play { ... }
.play .fa-pause { ... }
.pause .fa-play { ... }
.pause .fa-pause { ... }

ImageSlider

src/ImageSlider.js

  • Instance 생성
  • Private Field (일부 변수만 private으로 사용)과 Public Field
  • Constructor : 초기화해줄 element들을 constructor에 넣어서 class에서 instance를 생성할 때 실행시키도록 함
  • assignElement : slider-wrap을 먼저 탐색 후 sliderList, nextBtn, previousBtn을 탐색

export default class ImageSlider {
  #currentPostion = 0; // 현재 슬라이드 위치
  #slideNumber = 0; // 슬라이드 개수
  #slideWidth = 0; // 슬라이드 너비

  sliderWrapEl;
  sliderListEl;
  nextBtnEl;
  previousBtnEl;

  constructor() {

  }

  assignElement() {
    this.sliderWrapEl = document.getElementById('slider-wrap');
    this.sliderListEl = this.sliderWrapEl.querySelector('#slider');
    this.nextBtnEl = this.sliderWrapEl.querySelector('#next');
    this.previousBtnEl = this.sliderWrapEl.querySelector('#previous');
  }

}

src/index.js

import '../css/style.css';
import Slider from './ImageSlider';

const slider = new Slider();

Class Public & Private field (JavaScript)

초기화 (init)

  • constructor에 초기화
  • 슬라이드 개수
  • 슬라이드 너비 (초기값은 CSS에서 width:1000px이므로 clientWidth)
  • 슬라이더 리스트 너비
    슬라이드 리스트의 개수에 따라서 width를 설정해주는 로직으로 너비값 변경 시 다음 슬라이드로 교체
    width에 static으로 8000px로 지정한 것은 100%으로 변경
    슬라이드 개수 * 슬라이더 너비
  constructor() {
    this.assignElement();
    this.initSliderNumber();
    this.initSlideWidth();
    this.initSliderListWidth();
  }
  
  initSliderNumber() {
    this.#slideNumber = this.sliderListEl.querySelectorAll('li').length;
  }

  initSlideWidth() {
    this.#slideWidth = this.sliderListEl.clientWidth;
  }

  initSliderListWidth() {
    this.sliderListEl.style.width = `${this.#slideNumber * this.#slideWidth}px`;
  }

요소의 너비와 높이 얻기

스크롤, 슬라이드 등 동적 위치 구할 때 많이 활용됨

next/prev 버튼 개발

  • 버튼 이벤트 : 클릭 시 오른쪽으로 이동 실행
  • 좌우 이동 : 너비값에 따른 이동 생각하기
  • sliderListEl가 left:-1000px이고 width가 7000px이면 다음 슬라이드가 보여진다고 할 때 슬라이드너비가 0이면 위치값이 0
  • 1이 되면 -1000 옮겨지고, 2이면 -2000 ... 8이면 -8000 옮겨져야 보여지게 됨
  • 현재 위치값에 슬라이더 너비를 곱한 후 마이너스를 주면 해당 슬라이드로 넘어감
  • 오른쪽 : 현재 위치값에서 +1
    ㄴ 조건 : 경계값 처리 (마지막 슬라이드에서 다음으로 이동하면 첫번째로)
  • 왼쪽 : 현재 위치값에서 -1
    ㄴ 조건 : 경계값 처리 (첫번째 슬라이드에서 이전으로 이동하면 마지막으로)
  • 완료 후 constructor에 addEvent 발생시키기
  constructor() {
    this.assignElement();
    this.initSliderNumber();
    this.initSlideWidth();
    this.initSliderListWidth();
    this.addEvent();
  }
  
  addEvent() {
    this.nextBtnEl.addEventListener('click', this.moveToRight.bind(this));
    this.previousBtnEl.addEventListener('click', this.moveToLeft.bind(this));
  }
  
  moveToRight() {
    this.#currentPostion += 1;
    if (this.#currentPostion === this.#slideNumber) {
      this.#currentPostion = 0;
    }
    this.sliderListEl.style.left = `-${
      this.#slideWidth * this.#currentPostion
    }px`;
  }

  moveToLeft() {
    this.#currentPostion -= 1;
    if (this.#currentPostion === -1) {
      this.#currentPostion = this.#slideNumber - 1;
    }
    this.sliderListEl.style.left = `-${
      this.#slideWidth * this.#currentPostion
    }px`;
  }


💬 바닐라로 만드는 원리를 이해하기 위해 공부하지만 쓰다보면 왜 라이브러리가 활발하게 쓰이는지 알 수 있다 (생산성) 다만 원리를 알면 오류 수정이나 커스터마이징이 용이하다:)

기타 자료

익숙한 jQuery 라이브러리로 만드는 것이 아닌 SPA에서 Swiper 구현방법

💎 React.js로 구현하는 Swiper/Slider/Carousel

💎 Vue.js로 구현하는 Swiper

profile
필요한 내용을 공부하고 저장합니다.
post-custom-banner

0개의 댓글