[JavaScript 30 Days Challenge] JavaScript Drum Kit

yuza🍊·2021년 7월 14일
1
post-thumbnail

JavaScript 30 Days Challenge, Start!

프론트엔드 개발자를 꿈꾸는 사람으로서 자바스크립트의 기초를 튼튼히 해야할 필요성을 뼈저리게 느끼고 있는 요즘, 재밌는 챌린지가 있어서 도전해보기로 했다.
그런데, 그냥 영상 보고 코드 따라 치는 것으로는 부족할 것 같아 내가 덧붙이고 싶은 기능을 추가로 구현해보기로 마음 먹었다.
그리하여 챌린지의 첫번째 날, JavaScript로 드럼을 쳐보았다.

DAY 1-JavaScript Drum Kit

CODE

기본 구현 사항: 화면에 보이는 버튼(div)들 내에 있는 알파벳 키를 키보드로 누르면 버튼에 효과 + 드럼 소리 재생

1) Keydown event 발생
2) 'startPlay' event 활성화
3) 눌린 키보드 키의 KeyCode와 같은 data-key 속성을 가진 div와 audio를 각각 변수에 할당(keydownedBtn, keydownedSound)
4) 만약 keydownedSound가 존재하지 않으면 바로 return
5) keydownedBtn의 classList에 접근하여 'playing'을 추가
ex) class='key' -> class='key playing'
6) keydownedSound의 currentTime(음악의 재생 시점, 0인 경우 처음부터 재생)을 0으로 초기화
7) keydownedSound 재생됨
8) key 클래스를 가진 모든 태그들을 다 선택하여 Array로 변환 후, 변수(keys)에 할당
9) forEach 함수를 이용해 keys의 요소 하나하나에 transitionend 시 활성화되는 이벤트 'removeTransition'을 listen 시킴
10) removeTransition event는 'playing' 클래스를 제거

내가 추가한 기능: 버튼(div)을 마우스로 클릭 시 Key down시 발생하는 이벤트와 동일한 이벤트 발동

1) 위의 9번 과정에서 keys의 요소 하나하나에 'clickPlay' 이벤트도 listen 시킴(마우스 클릭 시 발동되도록)
2) this를 사용하여 내가 클릭한 div의 data-key와 같은 data-key 속성을 가진 audio를 변수 keydownedSound에 할당
3) this, 즉, 실행 중인 핸들러가 할당된 요소의 classList에 'playing'을 추가
4) keydownedSound의 currentTime(음악의 재생 시점, 0인 경우 처음부터 재생)을 0으로 초기화
5) keydownedSound 재생됨

What I Learned

처음 clickPlay 함수를 구현할 때는 'playing'을

event.target.classList.add('playing') 

이렇게 event.target에 추가하였다. 그랬더니...

이런 식으로 정말 내가 직접 클릭한 요소에만 playing 클래스가 추가되었다. 이 버그를 고치기 위해 이벤트 버블링과, this/event.target의 차이점 등을 공부하였다.

Event Bubbling

  • 한 요소에 이벤트가 발생하면, 그 요소의 핸들러가 동작한 뒤, 그 요소의 부모 요소, 부모의 부모 요소, 부모의 부모의 부모 요소...까지 타고 올라가면서(가장 최상단 요소에 이를 때까지) 각 요소들의 핸들러가 차례로 동작하는 것
  • 나는 자식 요소들 중 핸들러가 존재하는 요소에 이벤트가 발생했을 때만 버블링 현상이 발생하는 줄 알고 있었다. 즉,
<span onclick="alert('span')">
	FORM
	<div onclick="alert('div')">
    		DIV
    		<p>P</p>
  	</div>
</span>

이런 코드가 있다고 가정한다면, p 태그에는 아무런 핸들러가 할당되지 않은 상태여서 해당 요소를 클릭하더라도 버블링이 일어나지 않는다(즉, alert('div')와 alert('span')은 실행되지 않을 것)고 생각했었다.

그런데 실제로는 p 태그 부분을 클릭해도 alert('div')와 alert('span')가 실행되었다. div.onclick과 span.onclick이 그 안의 요소들에서 발생하는 이벤트들을 catch하고 있었기 때문이었다.

이런 성질을 이용하여 가장 바깥쪽 div에만 이벤트 핸들러를 할당해두면 내가 드럼 버튼의 어느 부분을 클릭해도 결국 내가 원하는 대로, 버튼의 가장 바깥쪽 div에만 'playing' 클래스를 추가할 수 있을 것 같았다.

그렇지만 event.target은 실제로 이벤트가 시작한 바로 그 target 요소를 가리키므로, 그 요소에 playing 클래스를 추가하면 상술한 버그가 계속 발생할 것이었다. 그러므로 나는 this를 사용해야 했다.

this는 현재 실행 중인 핸들러가 할당된 요소를 참조하므로,

this.classList.add("playing");

이렇게 코드를 수정하면, this가 핸들러가 동작한 div 요소를 가리키게 되므로 내가 원하는 대로 작동하게 된다.

div 내의 어떤 요소를 클릭하든지 실행 중인 핸들러가 할당된 요소인 div 태그에 playing 클래스가 추가되어 잘 동작한다.
GOOD!

이벤트 버블링과 this에 대해서는 잘 모르고 있었는데, 이번 기회를 통해 조금 갈피를 잡은 것 같아 기분이 좋다. 챌린지도 꼭 끝까지 이어나가야지.

참고 자료

profile
say hi to the world

0개의 댓글