freddy
느낌으로 남지않기
freddy
전체 방문자
오늘
어제
  • 분류 전체보기 (28)
    • HTML (2)
    • CSS (1)
    • JavaScript (8)
    • WebGL (0)
    • 개념정리 (0)
    • React (2)
    • ReactNative (4)
    • ERROR.LOG (3)
    • 설치 (2)
    • 챌린지 (0)
    • 책 (0)
    • 세미나 (2)
    • 일기장 (4)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • JavaScript
  • 앱이 계속 중지됨
  • Shorthand property names
  • Destructuring assignment
  • react
  • React Native
  • BOM 이란?
  • javascript 이벤트 위임
  • React-Native
  • Nullish coalescing operator
  • react 특징
  • javascript 최신문법
  • Github Actions
  • 프론트엔드
  • es11
  • react 기초
  • evnet 위임
  • Optional chainning
  • Spread syntax
  • em과rem차이
  • javscript 기초
  • react 사용하는 이유
  • JS
  • 리액트의 필요성
  • css variables
  • bitnami ubuntu
  • 브라우저 동작 원리
  • javascript30
  • 값식문
  • 최신JS문법

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
freddy

느낌으로 남지않기

JavaScript

JavaScript 30 Drum Kit 정리

2020. 12. 22. 09:26
반응형

요구사항

KeyBoard 입력을 받아 애니메이션 효과와 Drum 소리가 출력되게 vanilla JS를 이용해서 구현한다


기본 소스코드

  <div class="keys">
    <div data-key="65" class="key">
      <kbd>A</kbd>
      <span class="sound">clap</span>
    </div>
    <div data-key="83" class="key">
      <kbd>S</kbd>
      <span class="sound">hihat</span>
    </div>
    <div data-key="68" class="key">
      <kbd>D</kbd>
      <span class="sound">kick</span>
    </div>
    <div data-key="70" class="key">
      <kbd>F</kbd>
      <span class="sound">openhat</span>
    </div>
    <div data-key="71" class="key">
      <kbd>G</kbd>
      <span class="sound">boom</span>
    </div>
    <div data-key="72" class="key">
      <kbd>H</kbd>
      <span class="sound">ride</span>
    </div>
    <div data-key="74" class="key">
      <kbd>J</kbd>
      <span class="sound">snare</span>
    </div>
    <div data-key="75" class="key">
      <kbd>K</kbd>
      <span class="sound">tom</span>
    </div>
    <div data-key="76" class="key">
      <kbd>L</kbd>
      <span class="sound">tink</span>
    </div>
  </div>

  <audio data-key="65" src="sounds/clap.wav"></audio>
  <audio data-key="83" src="sounds/hihat.wav"></audio>
  <audio data-key="68" src="sounds/kick.wav"></audio>
  <audio data-key="70" src="sounds/openhat.wav"></audio>
  <audio data-key="71" src="sounds/boom.wav"></audio>
  <audio data-key="72" src="sounds/ride.wav"></audio>
  <audio data-key="74" src="sounds/snare.wav"></audio>
  <audio data-key="75" src="sounds/tom.wav"></audio>
  <audio data-key="76" src="sounds/tink.wav"></audio>

처리과정 & 코드분석

  1. keydown 이 될때마다 로그를 찍어 봤음

  2. keydown 됐을 때 실행할 익명함수 작성

  3. evnet를 찍었을 때 keyCode 속성이 나옴

  4. data-key를 이용함, event.keyCode 속성을 이용하여 동적으로 타겟을 잡음 key, audio 변수에 할당함

const audio = document.querySelect(`audio[data-key="${e.keyCode}"]`);

const key = document.querySelect(`key[data-key="${e.keyCode}"]`);
  1. currentTime 을 사용하여 시간을 0초로 설정함 (키보드 누를때 마다 audio 출력하기 위해)
 audio.currentTime = 0;
  1. play() 실행이 되면서 애니메이션 효과를 주기 위해
    key에 classList.add('playing') 추가함
key.classList.add('playing');
  1. 각 key에 적용된 CSS 효과를 지우기 위해 모든 key를 타겟 잡음 (querySelectAll로 타겟을 잡은 keys는 배열x 유사배열로(o) 값이 떨어짐)
const keys = document.querySelectAll('.key');
  1. keys를 forEach를 통해 반복하고 css 효과가 끝났을 때 실행 될 removeTransition 함수를 작성함
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
function removeTransition(e) {
    if (e.propertyName !== 'transform') return;
    this.classList.remove('playing');
}

8-1. removeTransition 함수에서 event를 찍어보니 css 전환이 완료된 evnet들이 찍혔고 거기에 propertyName 속성이 있었음 그 name이 'transform' 이 아닌 envet들은 return값을 주어 반환 시킴

8-2. removeTransition 안에서의 this 가 가리키는 곳은 이벤트가 발생한 key 이다.

key => key.addEventListener(...)

< this가 가리키는 부분 >
<div data-key="65" class="key">
      <kbd>A</kbd>
      <span class="sound">clap</span>
    </div> ...

결과

<script>

function playSound(e) {
  const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
  const key   = document.querySelector(`.key[data-key="${e.keyCode}"]`);

  if (!audio) return; // stop the function from running all together
  audio.currentTime = 0;
  audio.play();
  key.classList.add("playing");
}

function removeTransition(e) {
    if (e.propertyName !== 'transform') return;
    this.classList.remove("playing");
}

const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
window.addEventListener('keydown', playSound);

</script>

결과


찾아본 내용

data-key

custom data attribute 이다. 사용자가 임의로 만들고 생성한 속성 (data-*)
이 때문에 각각의 div 는 data-key 값을 인덱스처럼 사용할 수 있음.

currentTime

HTML audio/video DOM  currentTime 속성
currentTime 속성은 audio/video 재생의 현재 초를 설정하거나 반환함. 이 속성을 설정하면 재생이 지정된 위치로 이동함.

addEventListener("transitionend")

CSS 전환이 완료되면 transitionend 이벤트가 발생합니다.
참고 : CSS transition-property 속성이 제거 된 경우와 같이 완료 전에 전환이 제거되면 transitionend 이벤트가 발생하지 않습니다.

<kbd>

<kbd> 태그는 키보드 입력을 지정할 때 사용함

유사배열

유사배열은 []로 감싸져있지만 배열이 아닌 것을 유사배열이라 부른다.
배열과 유사배열의 큰 차이는 유사배열의 경우 배열의 메서드를 사용할 수 없습니다.
ex)forEach,map,filter..

유사배열이 배열의 메서드를 사용하려면 (call, apply, bind)이용
ex) Array.prototype.forEach.call(유사배열, 함수);
하면 유사배열도 배열의 메서드를 사용할 수 있게 됩니다.

querySelectAll

이 코드에서 keys가 (call, apply, bind) 하지않고 forEach를 사용할수 있었던 것은 querySelectAll이 정적 NodeList를 반환하기 때문 입니다. NodeList는 Array는 아니지만 forEach를 사용하여 반복할 수 있습니다.
반응형

'JavaScript' 카테고리의 다른 글

꼭! 알아야하는 JavaScript 최신문법 (ES6, ES11) 사용법 정리 (2)  (0) 2020.12.22
꼭! 알아야하는 JavaScript 최신문법 (ES6, ES11) 사용법 정리 (1)  (0) 2020.12.22
CSS Variables  (0) 2020.12.22
CSS + JS Clock 정리  (0) 2020.12.22
JavaScript 값, 식, 문,Primitive Type & Reference Type  (0) 2020.12.22
    'JavaScript' 카테고리의 다른 글
    • 꼭! 알아야하는 JavaScript 최신문법 (ES6, ES11) 사용법 정리 (2)
    • 꼭! 알아야하는 JavaScript 최신문법 (ES6, ES11) 사용법 정리 (1)
    • CSS Variables
    • CSS + JS Clock 정리
    freddy
    freddy

    티스토리툴바