JAVASCRIPT

게임 이펙트 음악 재생하기 복습하기

Kim do hyun 2023. 5. 3. 21:58
728x90
반응형
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");
const musicRepeat = musicWrap.querySelector("#control-repeat");
const musicListBtn = musicWrap.querySelector("#control-list");
const musicList = musicWrap.querySelector(".music__list");
const musicListUl = musicWrap.querySelector(".music__list ul");
const musicListClose = musicWrap.querySelector(".music__list h3 .close");

let musicIndex = 1;     //현재 음악 인덱스

// 음악 재생
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`;          //뮤직 파일
};

// 재생
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 == 1 ? musicIndex = 10 : musicIndex--;
    // if(musicIndex == 0) musicIndex = 10;
    loadMusic(musicIndex)
    playMusic();
    playListMusic();
};

// 다음 곡 듣기 버튼
const nextMusic = () => {
    musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++;
    // if(musicIndex == 10) musicIndex = 1;
    loadMusic(musicIndex)
    playMusic();
    playListMusic();
};

// 뮤직 진행바
musicAudio.addEventListener("timeupdate", 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}`;
});

// 진행 버튼 클릭
musicProgress.addEventListener("click", (e) => {
    let progressWidth = musicProgress.clientWidth;  //진행바 전체 길이
    let clickOffsetX = e.offsetX;   //진행바를 기준으로 측정되는 X값 좌표
    let songDuration = musicAudio.duration;     //오디오 전체 길이

    //백분위로 나눈 숫자에 다시 전체 길이를 곱해 현재 재생값으로 바꿈
    musicAudio.currentTime = (clickOffsetX /progressWidth) * songDuration;
});

// 반복 버튼 클릭
musicRepeat.addEventListener("click", () => {
    let getAttr = musicRepeat.getAttribute("class");
    
    switch(getAttr){
        case "repeat" : 
            musicRepeat.setAttribute("class", "repeat_one");
            musicRepeat.setAttribute("title", "한곡 반복");
        break;
        case "repeat_one" :
            musicRepeat.setAttribute("class", "shuffle");
            musicRepeat.setAttribute("title", "랜덤 반복");
        break;
        case "shuffle" :
            musicRepeat.setAttribute("class", "repeat");
            musicRepeat.setAttribute("title", "전체 반복");
    }
});

// 오디오가 끝나면
musicAudio.addEventListener("ended", () => {    //ended는 노래가 끝나면 실행되는 메서드
    let getAttr = musicRepeat.getAttribute("class");

    switch(getAttr){
        case "repeat" :
            nextMusic();
        break;
        case "repeat_one" :
            playMusic();
        break;
        case "shuffle" :
            let randomIndex = Math.floor(Math.random() * allMusic.length + 1); //랜덤 인덱스 생성

            do {
                randomIndex = Math.floor(Math.random() * allMusic.length + 1);
            } while (musicIndex == randomIndex);

            musicIndex = randomIndex;   //현재 인덱스를 랜덤 인덱스로 변경
            loadMusic(randomIndex);
            playMusic();
        break;
    }
    playListMusic();
});    

// 플레이 버튼 클릭
musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused");   //음악 재생중
    isMusicPaused ? pauseMusic() : playMusic();
});

// 이전곡 버튼 클릭
musicPrevBtn.addEventListener("click", () => {
    prevMusic();
});

// 다음곡 버튼 클릭
musicNextBtn.addEventListener("click", () => {
    nextMusic();
});

// 뮤직 리스트 버튼
musicListBtn.addEventListener("click", () => {
    musicList.classList.add("show");
});

musicListClose.addEventListener("click", () => {
    musicList.classList.remove("show");
});

// 뮤직 리스트 구현하기
for(let i=0; i<allMusic.length; i++){
    let li = `
    <li data-index="${i+1}">
        <span class="img">
            <img class="img" src="img/${allMusic[i].img}.png" alt="${allMusic[i].name}">
        </span>
        <span class="title">
            <strong>${allMusic[i].name}</strong>
            <em>${allMusic[i].artist}</em>
            <audio class="${allMusic[i].audio}" src="audio/${allMusic[i].audio}.mp3"></audio>
        </span>
        <span class="audio-duration" id="${allMusic[i].audio}">3:04</span>
    </li>
    `;

    // musicListUl.innerHTML += li;
    musicListUl.insertAdjacentHTML("beforeend", li);

    // 리스트에 음악 시간 불러오기
    let liAudioDuration = musicListUl.querySelector(`#${allMusic[i].audio}`);   //리스트에서 시간을 표시할 선택자
    let liAudio = musicListUl.querySelector(`.${allMusic[i].audio}`);           //리스트에서 오디오 파일 선택자
    liAudio.addEventListener("loadeddata", () => {
        let audioDuration = liAudio.duration;
        console.log(liAudio)
        let totalMin = Math.floor(audioDuration / 60);
        let totalSec = Math.floor(audioDuration % 60);
        if(totalSec < 10) totalSec = `0${totalSec}`;
        liAudioDuration.innerText = `${totalMin}:${totalSec}`;
        liAudioDuration.setAttribute("data-duration", `${totalMin}:${totalSec}`);
    });
}

// 뮤직 리스트를 클릭하면 재생
function playListMusic(){
    const musicListAll = musicListUl.querySelectorAll("li");    //뮤직리스트 목록

    for(let i=0; i<musicListAll.length; i++){
        let audioTag = musicListAll[i].querySelector(".audio-duration");

        musicListAll[i].setAttribute("onclick", "clicked(this)");

        if(musicListAll[i].classList.contains("playing")){
            musicListAll[i].classList.remove("playing");
            let dataAudioDuration = audioTag.getAttribute("data-duration");
            audioTag.innerText = dataAudioDuration;
        }
        if(musicListAll[i].getAttribute("data-index") == musicIndex){
            musicListAll[i].classList.add("playing");

            audioTag.innerText = "재생중";
        }
    }
}
playListMusic();

// 뮤직 리스크를 클릭하면
function clicked(el){
    let getIndex = el.getAttribute("data-index");
    musicIndex = getIndex;
    loadMusic(musicIndex);
    playMusic();
    playListMusic();
}


window.addEventListener("load", () => {
    loadMusic(musicIndex);
    musicAudio.play();
});

querySelector() 메서드는 지정된 셀렉터와 일치하는 첫 번째 문서 요소를 반환합니다. 이를 통해 DOM 트리에서 원하는 요소를 찾을 수 있습니다.

setAttribute() 메서드는 지정된 요소의 속성을 설정합니다. 이를 통해 요소의 특정 속성을 변경할 수 있습니다.

innerText 속성은 지정된 요소의 내부 텍스트 콘텐츠를 설정하거나 반환합니다. 이를 통해 요소의 내부 텍스트를 변경할 수 있습니다.

src 속성은 지정된 요소의 소스 URL을 설정하거나 반환합니다. 이를 통해 이미지나 오디오 등 요소의 소스를 변경할 수 있습니다.

play() 메서드는 HTML 오디오 요소를 재생합니다. 이를 통해 오디오 재생을 시작할 수 있습니다.

pause() 메서드는 HTML 오디오 요소를 일시 중지합니다. 이를 통해 오디오 재생을 일시 중지할 수 있습니다.

addEventListener() 메서드는 이벤트를 요소에 추가합니다. 이를 통해 요소에 대한 이벤트 핸들러를 등록할 수 있습니다.

Math.floor() 함수는 소수점 이하를 버리고 정수 부분만 반환합니다. 이를 통해 소수점 이하 값을 버리고 정수로 값을 변환할 수 있습니다.

 

// 음악 재생
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`;          //뮤직 파일
};

loadMusic(num) 함수는 음악 재생 기능의 핵심적인 부분입니다. 함수는 num 매개변수를 받습니다. 이 num은 현재 재생할 음악의 인덱스입니다.

함수의 첫 번째 줄은 현재 재생하는 음악의 이름을 musicName 요소에 출력합니다. allMusic[num-1].name 코드는 num 인덱스에서 1을 빼고, 그에 해당하는 allMusic 배열 요소의 name 속성을 반환합니다.

다음으로, 뮤직 아티스트 정보가 musicArtist 요소에 출력됩니다. 이 부분은 음악 이름과 출력 방식이 동일합니다.

musicView 요소는 음악 이미지를 보여주는 요소입니다. src 속성을 사용하여 현재 재생 중인 음악의 이미지 파일 경로를 지정합니다. allMusic[num-1].img 코드는 현재 재생 중인 음악 객체에서 img 속성 값을 가져와서 이미지 파일 경로를 만듭니다.

musicAudio 요소는 음악 파일 자체를 재생하는 HTML 오디오 요소입니다. src 속성을 사용하여 현재 재생 중인 음악 파일의 경로를 지정합니다. allMusic[num-1].audio 코드는 현재 재생 중인 음악 객체에서 audio 속성 값을 가져와서 오디오 파일 경로를 만듭니다.

따라서, loadMusic(num) 함수는 현재 재생 중인 음악의 정보를 출력하고, 음악 파일과 이미지 파일을 로드합니다. 이후 musicPlay 버튼을 클릭하면, musicAudio 요소에서 음악을 재생할 수 있습니다.