안녕하세요! 오늘은 게임 이펙트 중 뮤직듣기 작업을 진행해보겠습니다.
뮤직듣기!
스크립트_선택자
const musicWrap = document.querySelector(".music__wrap");
const musicName = musicWrap.querySelector(".music__control .title h3");
const musicArtist = musicWrap.querySelector(".music__control .title p");
const musicView = musicWrap.querySelector(".music__view .image img");
const musicAudio = musicWrap.querySelector("#main-audio");
const musicPlay = musicWrap.querySelector("#control-play");
const musicPrevBtn = musicWrap.querySelector("#control-prev");
const musicNextBtn = musicWrap.querySelector("#control-next");
const musicProgress = musicWrap.querySelector(".progress");
const musicProgressBar = musicWrap.querySelector(".progress .bar");
const musicProgressCurrent = musicWrap.querySelector(".progress .timer .current");
const musicProgressDuration = musicWrap.querySelector(".progress .timer .duration");
let musicIndex = 1; //현재 음악 인덱스
스크립트_음악 재생
window.addEventListener("load", () => {
loadMusic(musicIndex);
});
addEventListener 메서드를 사용하여 window 객체에서 load 이벤트를 청취하고 있습니다. 이벤트가 발생하면 loadMusic(musicIndex) 함수가 호출됩니다.
// 음악 재생
const loadMusic = (num) => {
musicName.innerText = allMusic[num-1].name; //뮤직 이름
musicArtist.innerText = allMusic[num-1].artist; //뮤직 아티스트
musicView.src = `img/${allMusic[num-1].img}.png`; //뮤직 이미지
musicView.alt = allMusic[num-1].name; //뮤직 이미지 alt
musicAudio.src = `audio/${allMusic[num-1].audio}.mp3`; //뮤직 파일
}
musicName 요소에는 해당 음악의 이름이 대입됩니다.
musicArtist 요소에는 해당 음악의 아티스트 이름이 대입됩니다.
musicView 요소의 src 속성에는 해당 음악의 이미지 파일 경로가 대입됩니다.
musicView 요소의 alt 속성에는 해당 음악의 이름이 대입됩니다.
musicAudio 요소의 src 속성에는 해당 음악의 오디오 파일 경로가 대입됩니다.
스크립트_재생, 정지, 이전 곡, 다음곡
// 재생
const playMusic = () => {
musicWrap.classList.add("paused");
musicPlay.setAttribute("title", "정지");
musicPlay.setAttribute("class", "stop");
musicAudio.play();
};
// 정지
const pauseMusic = () => {
musicWrap.classList.remove("paused");
musicPlay.setAttribute("title", "재생");
musicPlay.setAttribute("class", "play");
musicAudio.pause();
};
// 이전 곡 듣기
const prevMusic = () => {
// 첫 번째 방법
// musicIndex--;
// if(musicIndex == 0) musicIndex = 10;
// 두 번째 방법 (삼항 연산자)
musicIndex == 1 ? musicIndex = allMusic.length : musicIndex--;
loadMusic(musicIndex);
playMusic();
};
// 다음 곡
const nextMusic = () => {
// 첫 번째 방법
// musicIndex++;
// if(musicIndex == 10) musicIndex = 0;
// 두 번째 방법 (삼항 연산자)
musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++;
loadMusic(musicIndex);
playMusic();
};
playMusic 함수는 musicWrap 요소에 "paused" 클래스를 추가하고, musicPlay 요소의 title 속성과 class 속성을 변경하여 재생 버튼을 정지 버튼으로 바꾸고 음악을 재생합니다.
pauseMusic 함수는 musicWrap 요소에서 "paused" 클래스를 제거하고, musicPlay 요소의 title 속성과 class 속성을 변경하여 정지 버튼을 재생 버튼으로 바꾸고 음악을 일시정지합니다.
prevMusic 함수는 이전 곡을 재생합니다. musicIndex 변수를 감소시키거나, allMusic 배열의 길이에 따라서 이전 곡을 선택합니다. 선택된 곡 정보를 loadMusic 함수로 전달하고, playMusic 함수를 호출하여 음악을 재생합니다.
nextMusic 함수는 다음 곡을 재생합니다. musicIndex 변수를 증가시키거나, allMusic 배열의 길이에 따라서 다음 곡을 선택합니다. 선택된 곡 정보를 loadMusic 함수로 전달하고, playMusic 함수를 호출하여 음악을 재생합니다.
스크립트_버튼 클릭
// 플레이버튼 클릭
musicPlay.addEventListener("click",() => {
const isMusicPaused = musicWrap.classList.contains("paused"); // 음악 재생중
isMusicPaused ? pauseMusic() : playMusic();
});
// 이전곡 버튼 클릭
musicPrevBtn.addEventListener("click",() => {
prevMusic();
});
// 다음곡 버튼 클릭
musicNextBtn.addEventListener("click",() => {
nextMusic();
});
window.addEventListener("load", () => {
loadMusic(musicIndex);
});
isMusicPaused 값이 true라면 pauseMusic 함수를 호출하고, false라면 playMusic 함수를 호출합니다.
musicPrevBtn 요소를 클릭했을 때는 prevMusic 함수를 호출합니다.
musicNextBtn 요소를 클릭했을 때는 nextMusic 함수를 호출합니다.
window 객체의 load 이벤트가 발생했을 때는 loadMusic 함수를 호출하여 초기 음악 정보를 표시합니다.
스크립트_뮤직진행바
// 뮤직 진행 바
musicAudio.addEventListener("timeupdate", e => {
console.log(e);
const currentTime = e.target.currentTime; // 현재 재생되는 시간
const duration = e.target.duration; // 오디오의 총 길이
let progressWidth = (currentTime/duration) * 100; // 전체길이에서 현재 진행되는 시간을 백분위로 나누면
musicProgressBar.style.width = `${progressWidth}%`;
// 전체 시간
musicAudio.addEventListener("loadeddata",() => {
let audioDuration = musicAudio.duration;
let totalMin = Math.floor(audioDuration / 60);
let totalSec = Math.floor(audioDuration % 60);
if(totalSec < 10) totalSec = `0${totalSec}`;
musicProgressDuration.innerText = `${totalMin}:${totalSec}`;
});
// 진행 시간
let currentMin = Math.floor(currentTime / 60);
let currentSec = Math.floor(currentTime % 60);
if(currentSec < 10) currentSec = `0${currentSec}`;
musicProgressCurrent.innerText = `${currentMin}:${currentSec}`;
});
e.target.currentTime으로 현재 재생 중인 시간을 가져옵니다.
e.target.duration으로 오디오 파일의 전체 길이를 가져옵니다.
(currentTime/duration) * 100으로 현재 재생 시간이 전체 길이에 대한 백분위를 계산합니다. 이 값을 progressWidth 변수에 할당합니다.
musicProgressBar 요소의 style.width를 업데이트하여 진행 바를 표시합니다.
musicAudio 요소의 loadeddata 이벤트가 발생했을 때는 audioDuration 변수에 전체 길이를 할당하고, totalMin과 totalSec 변수에 분과 초를 계산합니다. 초가 10보다 작은 경우 0을 추가하여 두 자리 수로 표시합니다. 이 값을 musicProgressDuration 요소의 innerText에 할당하여 전체 시간을 표시합니다.
현재 재생 시간도 currentMin과 currentSec 변수에 계산합니다. 초가 10보다 작은 경우 0을 추가하여 두 자리 수로 표시합니다. 이 값을 musicProgressCurrent 요소의 innerText에 할당하여 현재 시간을 표시합니다.
스크립트_뮤직진행바 클릭
// 진행 버튼 클릭
musicProgress.addEventListener("click", (e) => {
let progressWidth = musicProgress.clientWidth; // 진행바 전체 길이
let clickedOffsetX = e.offsetX; // 진행바를 기준으로 측정되는 X 좌표값
let songDuration = musicAudio.duration; // 오디오 전체 길이
// 백분위로 나눈 숫자에 다시 전체 길이를 곱해서 현재 재생값으로 바꿈
musicAudio.currentTime = (clickedOffsetX / progressWidth) * songDuration;
})
마우스 클릭 이벤트가 발생하면, 해당 이벤트에 대한 정보를 담고 있는 객체 e를 매개변수로 전달받습니다.
그리고, e.offsetX를 사용해서 클릭한 위치에 대한 정보를 가져옵니다. offsetX 속성은, 이벤트가 발생한 엘리먼트 내에서의 X 좌표값을 나타냅니다.
다음으로, musicAudio.duration을 사용해서 음악 파일의 전체 길이를 가져옵니다.
그리고 나서, 클릭한 위치와 전체 길이의 비율을 구한 다음, musicAudio.currentTime 속성에 할당해서, 음악 파일의 재생 위치를 조정합니다.
완성된 페이지와 코드보기