[JS30] JavaScript30 Day 1
서론
JavaScript30 Challenge를 시작했다!
다른 라이브러리나 프레임워크를 사용하지 않고, 순수하게 Vanilla JS로만 진행하는 강의이다. JS의 기본은 Vanilla JS라고 생각하는데 이것조차 잘 다루지 못한다면, 라이브러리나 프레임워크를 잘 사용하지 못 할 것 같다는 생각에 시작하였다.
이 강의로 Vanilla JS 대한 이해가 상승하길 기대한다.
구현
Task
- 키보드 입력
- 입력 확인 (A, S, D, F, G, H, J, K, L 키인지)
- 입력에 따른 소리 출력
- 키를 연속해서 누르면, 오디오가 끝나지 않아도 처음부터 소리 다시 나게 함
- 키를 누를 때마다 transition 추가
- transition이 나타났다가 없어짐
1. 키보드 입력
키보드에 입력이 있으면, 즉 keydown이 있으면 어떤 키가 눌렸는지 확인해야 한다. 만약 A, S, D, F, G, H, J, K, L 키가 눌렸다면 2번으로 간다.
window.addEventListener('keydown', function (e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
});
data-key
란 강사님이 임의로 만든 프로퍼티인데, id나 class를 쓰는 것보다 이런 식으로 하는 것이 더 편해서 이리 한다고 한다. 그리고 개인이 만든 프로퍼티는 data-*
형식으로 이름을 짓는다고 한다. 그래서 화면 상의 키가 눌린다면, 그것에 해당하는 audio 요소를 상수에 할당하는 것이다.
2. 입력에 따른 소리 출력
맞는 입력이 들어오면 소리를 틀고, 아니라면 함수를 종료한다.
if (!audio) return;
audio.play();
이렇게 하면 문제가 생기는데, 바로 키를 누른 횟수만큼 소리가 안 난다. 즉, 오디오가 실행되고 있을 때 키를 누르면 이미 실행 중이기 때문에 오디오가 재생되지 않는다. 그래서 currentTime을 사용한다.
Reading currentTime returns a double-precision floating-point value indicating the current playback position, in seconds, of the audio.
공식 문서에 따르면, currentTime
은 재생 위치를 초로 반환한다. 그래서 audio.play();
이전에 audio.currentTime = 0;
를 추가하면, 매번 키를 누를 때마다 오디오가 처음부터 재생된다.
if (!audio) return;
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
3. 키를 누를 때마다 transition 추가
완성본을 보면 키를 누를 때마다 transition이 실행된다.
window.addEventListener('keydown', function (e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
if (!audio) return;
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
});
이런 식으로 하면 transition이 적용되지만, transition이 적용된 체로 계속 남아있는다. 그렇다면 키를 눌렀을 때 trasition을 적용했다가 지워야 한다. 여기서 setTimeOut
을 사용할 수도 있지만, 그렇게 한다면 trasition이 적용되는 시간과 setTimeOut
이 실행되는 시간을 동일하게 해야한다. 그럼 만약 css에서 transition duration을 변경한다면 다시 script 파일로 가 setTimeOut
의 시간도 변경해야 하는 약간의 번거로움이 생긴다.
const keys = document.querySelectorAll('.key');
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
그래서 위와 같이 querySelectorAll
로 key들을 배열의 형태로 다 상수에 할당한 다음, forEach
로 key 하나 하나에 접근한 다음 addEventListener
로 key의 transition이 끝난다면(transitionend) removeTransition
함수를 실행하는 것이다.
function removeTransition(e) {
if (e.propertyName !== 'transform') return;
this.classList.remove('playing');
}
여기서 console.log(e);
를 한다면 border의 각 면마다 transition을 적용하는 것을 볼 수 있다.
가장 마지막에 실행되는 TransitionEvent가 transform
이라, transform
이 실행되면 transition을 실행하는 클라스 playing
을 지우는 것이다.
TLD
프로퍼티로 DOM
객체에 접근할 수 있는 것도, transitionend
¤tTime
도, audio
라는 요소가 있는지도 처음 알았다! Transition이 끝났을 때 항상 setTimeOut
으로 처리하곤 했는데, 저런 JS API
가 있는게 신기했다. JS는 알면 알수록 참 별에 별게 다 있다. JS 고수가 되는 그 날을 위하여…!
최종 코드
function playSound(e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
if (!audio) return;
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);
댓글남기기