자바스크립트 음악 플레이어 만들기

버건디·2022년 11월 14일
1
post-thumbnail

🔍 구현해야할것들

🔍 HTML 코드

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://kit.fontawesome.com/412379eca8.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="style.css">
    <title>음악 플레이어</title>
</head>

<body>
    <div class="container">
        <h1>음악 플레이어</h1>
        <div class="music-container" id="musicContainer">
            <div class="music-info">
                <h4 id="title">노래 제목</h4>
                <div class="progress-container" id="progress-container">
                    <div class="progress" id="progress"></div>
                </div>
            </div>
            <audio id="audio" src="./music/hey.mp3" onloadstart="this.volume=0.005"></audio>
                <div class="img-container">
                    <img src="./images/summer.jpg" alt="cover" id="cover">
                </div>
                <div class="navigation">
                    <button id="prev" class="action-btn"><i class="fa-sharp fa-solid fa-backward"></i></button>
                    <button id="play" class="actiong-btn big"><i class="fa-solid fa-play"></i></button>
                    <button id="next" class="actiong-btn"><i class="fa-sharp fa-solid fa-forward"></i></button>
                </div>
            

        </div>

    </div>
    <script src="main.js"> </script>
</body>

</html>
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: linear-gradient(to bottom, rgb(222, 185, 185), #fff);
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.music-container {
  position: relative;
  margin: 100px 0;
  width: 400px;
  height: 100px;
  border-radius: 10px;
  background-color: #fff;
  box-shadow: 1px 20px 20px rgb(222, 185, 185);

}

.music-info {

  position: absolute;
  padding: 10px 10px 10px 150px;
  height: 50px;
  width: 350px;
  top: 0;
  left: 25;
  background-color: rgb(219, 193, 193);
  border-radius: 10px;
  opacity: 0;
  transform: translateY(0%);
  transition: transform 0.3s ease-in;
  z-index: 0;
  animation-play-state: paused;

}


.music-container.play .music-info {
  animation: showMusicInfo 0.5s forwards;
  transform: translateY(-100%);
  animation-play-state: running;

}

@keyframes showMusicInfo {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}


.music-info h4 {
  margin: 0;
}

.progress-container {
  margin: 5px 0;
  background-color: #fff;
  width: 100%;
  border-radius: 5px;
  cursor: pointer;
}

.progress {
  background-color: #fe8daa;
  height: 4px;
  width: 0%;
  border-radius: 5px;
  transition: width 0.1s linear;
}


.img-container {
  position: absolute;
  top: -30;
  left: 40;
  width: 110px;
  height: 110px;
}

.img-container::after {
  content: '';
  position: absolute;
  top: 40;
  left: 40;
  width: 20px;
  height: 20px;
  background-color: #fff;
  border-radius: 50%;
  z-index: 10;

}

.img-container img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
}

.navigation {
  position: absolute;
  right: 120;
  bottom: 10;
  width: 100px;
  display: flex;
}

.navigation button {
  color: rgb(223, 214, 214);
  background-color: #fff;
  border: none;
  padding: 10px;
  margin: 10px;
  cursor: pointer;
  font-size: 25px;
}

.actiong-btn.big {
  font-size: 40px;
}

.music-container.play .img-container img {
  animation: rotate 3s infinite linear;
  animation-play-state: running;
}



@keyframes rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

🔍 자바스크립트 코드

const playBtn = document.getElementById("play");
const musicContainer = document.getElementById("musicContainer");
const audio = document.getElementById("audio");
const prevBtn = document.getElementById("prev");
const nextBtn = document.getElementById("next");
const progress = document.getElementById("progress");
const progressContainer = document.getElementById('progress-container');
const imgCover = document.getElementById("cover");
const title = document.getElementById("title");

const songs = ["hey", "summer", "ukulele"];

let songIndex = 2;

loadSong(songs[songIndex]);

function loadSong(song) {
  title.innerText = song;
  audio.src = `http://127.0.0.1:5500/music/${song}.mp3`;
  imgCover.src = `http://127.0.0.1:5500/images/${song}.jpg`;
}

function playMusic() {
  musicContainer.classList.add("play");

  playBtn.innerHTML = `<i class="fa-solid fa-pause"></i>`;

  audio.play();
}

function pauseMusic(){
    musicContainer.classList.remove('play');
    playBtn.innerHTML = `<i class="fa-solid fa-play"></i>`;

    audio.pause();
}

function playPrevSong() {
    songIndex--;

    if (songIndex < 0) {
      songIndex = songs.length - 1;
    }
  
    loadSong(songs[songIndex]);
  
    playMusic();
}

function playNextSong (){
    songIndex++;

    if(songIndex > 2){
        songIndex = 0;
    }

    loadSong(songs[songIndex]);
    playMusic();
}

function updateProgress(e){
    const {duration, currentTime} = e.srcElement;

    const progressPer = (currentTime / duration) * 100;

    progress.style.width = `${progressPer}%`;
}

function changeProgress(e){

    const width = e.target.clientWidth; // 전체 넓이

    const offsetX = e.offsetX; // 현재 x 좌표;

    const duration = audio.duration; // 재생길이

    audio.currentTime = (offsetX / width) * duration; 

}

playBtn.addEventListener("click", () => {
    const isPlaying = musicContainer.classList.contains('play');

    if(isPlaying){
        pauseMusic();
    } else{
        playMusic();
    }
});

prevBtn.addEventListener("click", playPrevSong);
nextBtn.addEventListener('click', playNextSong);
audio.addEventListener('ended', playNextSong);
audio.addEventListener('timeupdate', updateProgress);

progressContainer.addEventListener('click', changeProgress);

🔍 알아두어야 할 점

  1. 서로 겹치는 섹션이 많다보니 CSS position 배치가 굉장히 어려웠다.

  2. 음악이 재생될때 music-info 의 opacity가 0에서 1로 서서히 바뀌어야했는데, 1로 바뀌자마자 music-info 가 사라지는 오류가 발생했다. animation-fill-mode 에서 forwards 속성을 이용해서 애니메이션의 마지막 적용값을 유지시켜주었다. 반대로 backwards 속성을 적용시키면 애니메이션 적용 전의 속성으로 유지된다.

  3. progress 바 이동 이벤트를 만들때 전체 넓이를 구할때는 e.target을 쓰고 현재의 x좌표를 구할때는 e.offsetX 를 사용했는데 차이점을 구분해야했다.

🔍 완성 화면

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글