The journey to becoming a developer

My future is created by what I do today, not tomorrow.

Projects

[JavaScript30] Day 1 : JavaScript Drum Kit

Millie 2021. 10. 7. 17:56

Project Introduction

A부터 L까지, 키보드의 키를 누르게 되면 해당하는 드럼의 소리가 나오게 되는 간단한 프로젝트이다. 

또한 키를 눌렀을 때, 해당하는 버튼이 마치 불이 켜지는 것 같은 CSS Animation 효과도 곁들였다.

CSS 스타일링은 기본적으로 제공해 주긴 하지만, 연습도 할 겸 내가 직접 코드를 짜 보았다.

 

사실 이 프로젝트는 키보드 키를 눌렀을 때 소리나는 기능밖에 없어서 단순하지만, 여기에서도 꼭 챙겨야 할 것들이 있다. 핵심은 역시 이벤트를 잘 핸들링하는 것이지만, 이벤트 추가와 제거만 한다고 끝이 아니다. 예외 처리, keycode, transitionend 같은 이벤트를 알아야 순조롭게 만들 수 있다. 그래서 그런 것들을 중심으로, 잊지 않기 위해 포스팅을 해 본다.

 

JavaScript

전체 소스코드

const keys = document.querySelectorAll('.key');

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; // rewind to the start
  audio.play();
  key.classList.add('playing');
}

function removeTransition(e) {
  if (e.propertyName !== 'transform') return; // skip it if it is not a transform
  this.classList.remove('playing');
}

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

 

 

 

1. classList, transitionend

  • classList : add, remove, toggle 등을 쓸 수 있다. DOM 객체에 class를 더하거나 삭제할 수 있고, 토글링도 할 수 있다. 
    • 이 프로젝트에서는 해당하는 키가 눌렸을 때, classList.add()로 playing이라는 클래스가 추가되면서 CSS 스타일링을 주게 된다. 
    • 키에서 손가락을 뗐을 때에는 다시 playing이라는 클래스가 제거되어 원래 스타일로 돌아가야 하는데 이때 classList.remove()를 쓰면 된다.  
  • 그렇다면 언제 클래스를 제거해야 하는가가 관건이 된다. 이 강의에서는 "transitionend"라는 것을 알려준다. 
    • 이것은 CSS에서 transition이라는 애니메이션이 끝났을 때 발동하는 것이다. (이렇게 세부적인 것까지 이벤트가 정의되어 있음에 놀라웠다. 브라우저 API!)
    • 'transition을 할 때 지정한 시간을 반영해서 setTimeout을 이용할 수 있지 않을까?' 라고 생각할 수도 있겠지만, 강사는 이건 좋은 방법은 아니라고 하였다. CSS transition의 0.07초에 맞춘다는 것인데, 이렇게 하면 동작은 하겠지만 CSS를 수정할 때 JS도 함께 수정해야 하는 번거로움이 있다. 

 

2. keycode

keydown 이벤트의 event 객체를 console.log로 찍어 보면 이렇게 나온다. 내가 q를 눌렀더니, keyCode는 81이라고 알려준다. 그래서 e.keyCode로 하면 해당하는 키의 코드를 얻을 수 있게 된다. 

 

혹은 keyCode를 직관적으로 알려주는 사이트에서 알아봐도 된다. 

http://keycode.info/ 에 들어가면, 어떤 키가 어떤 code를 가지고 있는지 보여 준다. 

 

예를 들어 a를 누르면 이렇게 나온다. 

그런데 VS Code에서 "keyCode is deprecated"라고 알려준다. 구글링을 해 보니 요즘은 KeyboardEvent을 대신 쓴다고 한다. 

 

3. HTML tag - <kbd>

<kbd>라는 태그가 생소하여 알아보았다.

MDN에도 설명이 잘 되어 있지만, 이것에 대해 좀 더 쉽게 설명한 블로그가 있다. 

 

HTML

Tag

Use the HTML kbd tag to semantically denote your text as a keyboard command. Great for documentations…

medium.com

Keyboard command text를 <kbd>로 감싸게 되면 좀 더 의미있게 쓸 수 있는 것이다. 이것으로 감싸게 되면 브라우저의 기본 스타일이 적용된다. 기본 스타일이라고 해봤자 사실 monospace font-family가 적용된 것 이거 하나뿐이다. 

 

사실 그러면 <code> 태그와 무엇이 다르냐 하는 의문이 생길 수 있다. 이것도 역시 기본 스타일로 monospace font-family가 적용되기 때문이다. 간단히 말하면 태그에서도 보이듯 의미상으로 다르다. 

  • <kbd> : 키보드, 음성 입력, 기타 입력 장치에서 사용자 입력을 나타내는 텍스트이다.
  • <code> : 컴퓨터 코드의 일부분을 나타내는 텍스트이다. 

즉 Drum Kit에서는 키보드 입력을 나타내야 하기 때문에 <kbd>라는 태그를 사용한 것이다. 더 semantic한 방법이다. 

 

4. keydown event 

여기서는 window에 keydown 이벤트가 발생하면 콜백 함수를 실행시키는 식으로 코드를 짠다. 

key와 관련된 이벤트는 keypress, keyup 등도 있는데 이것들을 잘 구별해서 때에 맞게 쓰는 것이 중요하다고 생각했다. (추후에 이 세 가지를 잘 정리해야겠다.) 

 

5. currentTime = 0 설정 

key를 손가락을 떼지 않고 계속 누르고 있을 때, 혹은 key를 빠른 속도로 연속해서 눌렀을 때 소리가 반복해서 날 수 있도록 해야 한다.

재생되는 audio의 길이보다 더 빠르게 입력이 발생했을 때, 그 audio의 재생 시간이 처음으로 되돌아 가야 한다. 

audio에 currentTime을 0으로 설정하여 다시 처음으로 갈 수 있도록(rewind) 설정해준다.

그러면 재생 시간이 처음으로 가게 되고, 처음부터 다시 재생이 된다. 

 

Bug & Solution 

key를 계속 누른 후 손가락을 뗐을 때, 원래는 playing 클래스가 제거되어야 하지만 제거되지 않아서 CSS Styling이 계속 키를 누른 상태의 것으로 유지되는 현상이 발생한다. 즉 classList.remove가 되지 않는 것. 

if (e.propertyName !== 'transform') return;

위의 코드를 removeTransition 함수에서 제거했더니 정상 작동한다. 

Web bose 강사가 왜 이 코드를 넣은건지 의도를 파악하지 못했다. 없어야 잘 되는데 말이다. (혹시 아시는 분이 계신다면 댓글로 알려주세요) 


Review

자바스크립트 코드라인이 약 20줄밖에 되지 않는 아주 작은 프로젝트였지만 핵심 개념이나 로직을 모른다면 구현하기 꽤나 쉽지 않은 프로젝트이다. if문으로 예외를 처리하는 것, this의 사용, 내가 몰랐던 이벤트들 등 많은 것을 알아간 알찬 프로젝트였다. 

JavaScript에서 audio와 keyboard 관련한 이벤트는 잘 다뤄본 적이 없는데 이런 식으로 특정 요소에 소리를 입히고 싶다면 어떻게 해야 하는지에 대한 감도 익힐 수 있었다. 

클릭했을 때도 해당하는 드럼 소리가 날 수 있게 응용해보고 싶다.