본문 바로가기
WEB Basic/JavaScript

[JavaScript30] 01. JavaScript Drum Kit - 키보드 입력 이벤트

by Devinus 2021. 3. 4.

JavaScript30 - 바닐라 자바스크립트 Day1

JS30 - JavaScript Drum Kit

 

1. 소스코드 - HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JS Drum Kit</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

<!-- 웹 페이지의 화면 표현에 관련된 부분 -->
  <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>

<script>
  // playing 함수는 키 입력을 받았을 때 호출할 함수이다
  function playing(e){
    // audio의 data-key속성값이 입력받은 키의 값인 앨리먼트를 가져와 audio 상수에 할당
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    // class가 key인 앨리먼트의 data-key속성값이 입력받은 키의 값인 앨리먼트를 가져와 key 상수에 할당
    const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);

    // 만약 입력된 키가 정상적인(HTML코드에 태그로 등록된) 키가 아니라면 함수를 종료
    if(!audio) return;
    // 입력받은 키에 해당하는 audio태그의 src의 재생시간을 0으로 할당
    // 재생시간을 0으로 할당하는 이유는 동일한 키의 연속 입력 시 먼저 입력된 소리가 끝날 때 까지 기다리지 않고 소리를 처음부터 다시 재생 -> 반복해서 입력 가능
    audio.currentTime = 0;
    // 입력받은 키에 해당하는 audio태그의 src 재생
    audio.play();
    // 화면에 해당 키가 눌렸는지 CSS로 변화를 주기 위해 입력받은 키에 해당하는 key 클래스를 가진 앨리먼트 class에 'playing'을 추가
    key.classList.add('playing');
  }
  
  // 키를 눌렀을 때 화면 표현에 대한 처리를 하기위한 함수
  function removeTransition(e){
    // e.propertyName은 transition과 연관된 속성 이름이다.
    // e.propertyName이 'transform'이 아니라면 함수 종료
    if(e.propertyName !== 'transform') return;
    console.log(e.propertyName);
    // 변화가 끝나면(transitionend) 키가 눌렸을때 화면에 변화를 주기 위해 추가했던 class 'playing'을 제거해서 원래대로 변경
    this.classList.remove('playing');
  }
  // class가 key인 태그들을 가져와 상수 keys에 할당
  const keys = document.querySelectorAll('.key');
  // keys 배열을 forEach 메서드를 이용해 배열의 앨리먼트 key들에 removeTransition함수를 실행하는 'transitionend'이벤트를 추가한다.
  // 'transitionend'이벤트는 변화(css transition)가 끝났을 때 실행되는 이벤트이다.
  keys.forEach(key => key.addEventListener('transitionend', removeTransition));

  // 키보드 버튼이 눌렸을 때 playing 함수를 실행
  window.addEventListener('keydown', playing);
</script>


</body>
</html>

 


 

2. 주목할 만한 문법

 

2.1. window.addEventListener('이벤트명', 함수)

- window객체에 이벤트를 추가하는 메서드

2.1.1. 'keydown' 이벤트

- 키보드가 눌렸을 때 이벤트가 발생

// 키보드 버튼이 눌렸을 때 playing 함수를 실행
window.addEventListener('keydown', playing);

 

2.2. document.querySelector(`앨리먼트[속성 값="${백 틱 표현식}"]`);

- document.querySelector( ): 앨리먼트를 선택해서 앨리먼트값을 가져오는 메서드

- 앨리먼트[속성 = "값"]: 앨리먼트의 속성이 값인 앨리먼트를 선택

- ${백 틱 표현식}: 문자열 내에서 변수나 함수를 표현할 수 있는 표현식, python의 f-string과 비슷하다.

// audio의 data-key속성값이 입력받은 키의 값인 앨리먼트를 가져와 audio 상수에 할당
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
// class가 key인 앨리먼트의 data-key속성값이 입력받은 키의 값인 앨리먼트를 가져와 key 상수에 할당
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);

 

2.3. 앨리먼트.classList.add('클래스명');

- 앨리먼트에 '클래스명' 클래스를 추가하는 메서드

// 화면에 해당 키가 눌렸는지 CSS로 변화를 주기 위해 입력받은 키에 해당하는 key 클래스를 가진 앨리먼트 class에 'playing'을 추가
key.classList.add('playing');

 

2.4. 앨리먼트.classList.remove('클래스명');

- 앨리먼트에 '클래스명' 클래스를 제거하는 메서드

// 변화가 끝나면(transitionend) 키가 눌렸을때 화면에 변화를 주기 위해 추가했던 class 'playing'을 제거해서 원래대로 변경
this.classList.remove('playing');

 

2.5. 배열.forEach(key => 배열.addEventListener('이벤트명', 함수));

- 배열의 요소 각각에 주어진 함수를 실행하는 메서드

// keys 배열을 forEach 메서드를 이용해 배열의 앨리먼트 key들에 removeTransition함수를 실행하는 'transitionend'이벤트를 추가한다.
// 'transitionend'이벤트는 변화(css transition)가 끝났을 때 실행되는 이벤트이다.
keys.forEach(key => key.addEventListener('transitionend', removeTransition));

참고: developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

 

Array.prototype.forEach() - JavaScript | MDN

forEach() 메서드는 주어진 함수를 배열 요소 각각에 대해 실행합니다. The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://git

developer.mozilla.org

 

2.6. 앨리먼트.addEventListener('이벤트명', 함수)

- 앨리먼트에 이벤트를 추가하는 메서드

2.6.1. 'transitionend' 이벤트

- transition(전이)가 끝났을 때 이벤트가 발생

// keys 배열을 forEach 메서드를 이용해 배열의 앨리먼트 key들에 removeTransition함수를 실행하는 'transitionend'이벤트를 추가한다.
// 'transitionend'이벤트는 변화(css transition)가 끝났을 때 실행되는 이벤트이다.
keys.forEach(key => key.addEventListener('transitionend', removeTransition));

참고: www.w3schools.com/jsref/event_transition_propertyname.asp

 

TransitionEvent propertyName Property

TransitionEvent propertyName Property ❮ DOM Events ❮ TransitionEvent Example Get the property name associated with the transition: document.getElementById("myDIV").addEventListener("transitionend", myFunction); function myFunction(event) {   this.inne

www.w3schools.com