티스토리 뷰

Javascript/연습, 실습

뮤직 플레이

SBDB_뉴유 2022. 4. 14. 16:56
const musicWrap = document.querySelector(".wrap__music");
        
const musicImg = musicWrap.querySelector(".music__img img");

const musicSong = musicWrap.querySelector(".music__song");
const musicName = musicSong.querySelector(".name");
const musicArtist = musicSong.querySelector(".artist");

const musicProgress = musicWrap.querySelector(".music__progress");
const musicProgressBar = musicProgress.querySelector(".bar");
const musicAudio = musicProgress.querySelector("#main-audio");
const musicProgressCurrent = musicProgress.querySelector(".current");
const musicProgressDuration = musicProgress.querySelector(".duration");

const musicControl = musicWrap.querySelector(".music__control");
const musicPlay = musicControl.querySelector("#control-play");
const musicPrev = musicControl.querySelector("#control-prev");
const musicNext = musicControl.querySelector("#control-next");
const musicRepeat = musicControl.querySelector("#control-repeat");
const musicListBtn = musicControl.querySelector("#control-list");

const musicList = musicWrap.querySelector(".music__list");
const musicListClose = musicList.querySelector(".close");
const musicListUl = musicList.querySelector(".list ul");

let musicIndex = Math.floor((Math.random() * allMusic.length) + 1 );

// 음악정보 뿌러주기
function loadMusic(num){
    musicImg.src = `images/${allMusic[num - 1].img}.jpg`;
    musicImg.alt = allMusic[num - 1].name;
    musicName.innerText = allMusic[num - 1].name;
    musicArtist.innerText = allMusic[num - 1].artist;
    musicAudio.src = `songs/${allMusic[num - 1].audio}.mp3`;
}

// 음악재생
function playMusic(){
    musicWrap.classList.add("paused");
    musicPlay.innerText = "pause";
    musicPlay.setAttribute("title", "재생")
    musicAudio.play();
}

// 음악정지
function pauseMusic(){
    musicWrap.classList.remove("paused");
    musicPlay.innerText = "play_arrow";
    musicPlay.setAttribute("title", "정지")
    musicAudio.pause();
}

// 이전음악
function prevMusic(){
    musicIndex == 1 ? musicIndex = allMusic.length : musicIndex--;
    loadMusic(musicIndex);
    playMusic();
}

// 다음음악
function nextMusic(){
    musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++;
    loadMusic(musicIndex);
    playMusic();
}

// 뮤직 진행바
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}`;
});

// 재생/정지 버튼
musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused")
    isMusicPaused ? pauseMusic() : playMusic();
})

// 이전 버튼
musicPrev.addEventListener("click", () => {
    prevMusic();
    playListMusic();
});

// 다음 버튼
musicNext.addEventListener("click", () => {
    nextMusic();
    playListMusic();
});

// 진행 버튼
musicProgress.addEventListener("click", (e) => {
    let progressWidth = musicProgress.clientWidth;
    let clickedOffsetX = e.offsetX;
    let songDuration = musicAudio.duration

    musicAudio.currentTime = (clickedOffsetX / progressWidth) * songDuration;
    playMusic();
    playListMusic();
})

// 반복 버튼
musicRepeat.addEventListener("click", (e) => {
    let getText = musicRepeat.innerText;

    switch(getText){
        case "repeat":
            musicRepeat.innerText = "repeat_one";
            musicRepeat.setAttribute("title", "한곡 반복")
        break;
        case "repeat_one":
            musicRepeat.innerText = "shuffle";
            musicRepeat.setAttribute("title", "랜덤 반복")
        break;
        case "shuffle":
            musicRepeat.innerText = "repeat";
            musicRepeat.setAttribute("title", "전체 반복")
        break;
    };
});

// 오디오가 끝나고
musicAudio.addEventListener("ended", () => {
    let getText = musicRepeat.innerText;

    switch(getText){
        case "repeat":
            nextMusic();
        break;
        case "repeat_one":
            loadMusic(musicIndex);
            playMusic();
            playListMusic();
        break;
        case "shuffle":
            let randIndex = Math.floor((Math.random() * allMusic.length) + 1);
            do {
                randIndex = Math.floor((Math.random() * allMusic.length) + 1);
            } while (musicIndex == randIndex);
            // musicIndex = randIndex;
            loadMusic(randIndex);
            playMusic();
            playListMusic();
        break;
    }
})

// 뮤직 리스트 버튼
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}">
            <div>
                <em>${allMusic[i].name}</em>
                <p>${allMusic[i].artist}</p>
            </div>
            <audio class="${allMusic[i].audio}" src="songs/${allMusic[i].audio}.mp3"></audio>
            <span id="${allMusic[i].audio}" class="audio-duration">3:36</span>
        </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;
        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 j=0; j<musicListAll.length; j++){
        let audioTag = musicListAll[j].querySelector(".audio-duration");

        if(musicListAll[j].classList.contains("playing")){
            musicListAll[j].classList.remove("playing");
            let adDuration = audioTag.getAttribute("data-duration");
            audioTag.innerText = adDuration;
        }

        if(musicListAll[j].getAttribute("data-index") == musicIndex){
            musicListAll[j].classList.add("playing");
            audioTag.innerText = "재생중";
        }

        musicListAll[j].setAttribute("onclick", "clicked(this)")
    }
}

// 뮤직 리스트의 곡 클릭하기
function clicked(el){
    let getLiIndex = el.getAttribute("data-index");
    musicIndex = getLiIndex;
    loadMusic(musicIndex);
    musicList.classList.remove("show");
    playMusic();
    playListMusic();
}

// 페이지 로딩 후 실행
window.addEventListener("load", () => {
    loadMusic(musicIndex);
    playListMusic();
})
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: Poppins;
}
:root {
    --pink : #FF74A4;
    --violet : #9F6EA3;
    --white : #fff;
    --lightshadow : rgba(0, 0, 0, 0.15);
    --lightblack : #515C6F;
    --pinkshadow : #FFCBDD;
    --darkwhite : #CECACA;
}
body {
    height: 100vh;
    background: linear-gradient(var(--pink) 0%, var(--violet) 100%);
}
.wrap__music {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100%;
    user-select: none;
}
.music__inner {
    width: 380px;
    padding: 25px 30px;
    overflow: hidden;
    position: relative;
    border-radius: 15px;
    background: var(--white);
    box-shadow: 0px 6px 15px var(--lightshadow);
}
.music__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.music__top i {
    font-size: 30px;
    color: var(--lightblack);
}
.music__top h3 {
    font-size: 18px;
    color: var(--lightblack);
    font-weight: 500;
}
.music__img {
    width: 100%;
    height: 256px;
    overflow: hidden;
    border-radius: 15px;
    margin-top: 25px;
    box-shadow: 0px 6px 12px var(--lightshadow);
}
.music__img img {
    width: 100%;
    height: 100%;
    vertical-align: top;
    object-fit: cover;
}
.music__song {
    text-align: center;
    margin: 30px;
}
.music__song p {
    color: var(--lightblack);
}
.music__song p.name {
    font-size: 21px;
}
.music__song p.artist {
    font-size: 18px;
    opacity: 0.9;
    line-height: 35px;
    font-weight: 300;
}
.music__progress {
    height: 6px;
    width: 100%;
    border-radius: 10px;
    background: #f0f0f0;
    cursor: pointer;
}
.music__progress .bar {
    height: inherit;
    width: 0%;
    position: relative;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--pink) 0%, var(--violet) 100%);
}
.music__progress .timer {
    margin-top: 2px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--lightblack);
    font-size: 0.9em;
    pointer-events: none;
}
.music__control {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 40px;
}
.music__control i {
    font-size: 28px;
    user-select: none;
    background: linear-gradient(90deg, var(--pink) 0%, var(--violet) 100%);
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}
.music__control i:nth-child(2),
.music__control i:nth-child(4) {
    font-size: 40px;
}
.music__control .play-pause {
    width: 54px; height: 54px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(var(--white) 0%, var(--darkwhite) 100%);
    box-shadow: 0px 0px 0px 2px var(--pink);
    z-index: 1;
}
.music__control .play-pause::before {
    content: '';
    width: 40px; height: 40px;
    border-radius: inherit;
    background: linear-gradient(var(--pink) 0%, var(--violet) 100%);
    position: absolute;
    z-index: -1;
}
.music__control .play-pause i {
    -webkit-text-fill-color: var(--white);
    opacity: 0.8;
}
.music__list {
    position: absolute;
    background: var(--white);
    width: 100%;
    left: 0;
    z-index: 10;
    border-radius: 10px;
    padding: 15px 30px;
    box-shadow: 0 -5px 10px rgba(0,0,0,0.1);
    transition: all 0.15s ease-out;
    bottom: -400px;
    opacity: 0;
    pointer-events: none;
}
.music__list.show {
    bottom: 0px;
    opacity: 1;
    pointer-events: auto;
}
.music__list .title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--lightblack);
    margin-bottom: 10px;
}
.music__list .title .queue {
    vertical-align: -5px;
}
.music__list .list {
    color: var(--lightblack);
}
.music__list .list > ul {
    max-height: 260px;
    margin: 10px 0;
    overflow: auto;
}
.music__list .list > ul::-webkit-scrollbar {
    width: 0;
}
.music__list .list > ul > li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #e5e5e5;
    padding-bottom: 5px;
    margin-bottom: 5px;
}
.music__list .list > ul > li.playing {
    color: var(--pink);
}
.music__list .list > ul > li > div em {
    font-style: normal;
}
.music__list .list > ul > li > div p {
    opacity: 0.8;
}​

'Javascript > 연습, 실습' 카테고리의 다른 글

타자 연습  (0) 2022.04.14
카드 뒤집기  (0) 2022.04.14
js로 css 제어하기  (0) 2022.02.11
puzzle 만들기  (0) 2022.01.29
댓글
© 2018 webstoryboy