music player 구현

이인재·2022년 9월 24일
0

Javascript

목록 보기
26/28

결과

코드

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Music Player</title>
    <link rel="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"/>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="player-container">
        <div class="img-container">
            <img src="img/이인재-1.jpg" alt="Album Art">
        </div>
        <h2 id="title">Electric Chill Machine</h2>
        <h3 id="artist">이인재</h3>
        <audio src="music/이인재-1.mp3"></audio>
        <!-- progress -->
        <div class="progress-container" id="progress-container">
            <div class="progress" id="progress"></div>
            <div class="duration-wrapper">
                <span id="current-time">0:00</span>
                <span id="duration">2:06</span>
            </div>
        </div>
        <!-- Controls -->
        <div class="player-controls">
            <i class="fas fa-backward" id="prev" title="Previous"></i>
            <i class="fas fa-play main-button" id="play" title="Play"></i>
            <i class="fas fa-forward" id="next" title="Next"></i>
        </div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
</body>
</html>

JavaScript

const image = document.querySelector('img');
const title = document.getElementById('title');
const artist = document.getElementById('artist');
const music = document.querySelector('audio');
const progressContainer = document.getElementById('progress-container');
const progress = document.getElementById('progress');
const currentTimeEl = document.getElementById('current-time');
const durationEl = document.getElementById('duration');
const prevBtn = document.getElementById('prev');
const playBtn = document.getElementById('play');
const nextBtn = document.getElementById('next');

song list

const songs = [
    {
        name: '이인재-1',
        displayName: 'Electric Chill Machine',
        artist: '이인재',

    },
    {
        name: '이인재-2',
        displayName: 'Seven Nation Army (Remix)',
        artist: '이인재',
    },
    {
        name: '이인재-3',
        displayName: 'Goodnight, Disco Queen',
        artist: '이인재',
    },
    {
        name: 'metric-1',
        displayName: 'Front Row (Remix)',
        artist: '제로',
    },
];

song play & pause

// 실행되고 있는 지 확인
let isPlaying = false;

// 실행
function playSong() {
    isPlaying = true;
    playBtn.classList.replace('fa-play', 'fa-pause');
    playBtn.setAttribute('title', 'Pause');
    music.play();
}

// 중지
function pauseSong() {
    isPlaying = false;
    playBtn.classList.replace('fa-pause', 'fa-play');
    playBtn.setAttribute('title', 'Play');
    music.pause();
}

// 이벤트리스너 적용
playBtn.addEventListener('click', () => (isPlaying ? pauseSong() : playSong()));

먼저 실행되지 않는 것을 디폴트로 해서 false로 해놓는다.
addEventListener로 click하면 이벤트가 실행되도록 하고,

실행 중일 때는 class를 변경하며 중지 아이콘이 보여질 수 있게 한다.
또한 HTML에 있던 title 속성을 Pause로 바꿔준다.

중지되어있을 때는 class를 변경하며 재생 아이콘이 보여질 수 있게 한다.
또한 HTML에 있던 title 속성을 Play로 바꿔준다.

loadSong

// DOM 활용
function loadSong(song) {
    title.innerText = song.displayName;
    artist.innerText = song.artist;
    music.src = `music/${song.name}.mp3`;
    image.src = `img/${song.name}.jpg`;
}

title과 artist명은 위에 적었던 song list에 적혀있는 속성들로 텍스트가 표시되게 하고,

템플릿 리터럴을 이용해 music과 이미지를 불러온다.

Current, Previous, Next Song

// 현재 곡
let songIndex = 0;

// 이전 곡
function prevSong() {
    songIndex--;
    if (songIndex < 0) {
        songIndex = songs.length - 1;
    }
    loadSong(songs[songIndex]);
    playSong();
}

// 다음 곡
function nextSong() {
    songIndex++;
    if (songIndex > songs.length - 1) {
        songIndex = 0;
    }
    loadSong(songs[songIndex]);
    playSong();
}

// 로드
loadSong(songs[songIndex]);

songIndex의 디폴트 값을 0으로.

이전 곡으로 이동할 때에는 songIndex--로 전 곡으로 이동한다.

하지만? 0보다 전으로 가면 -1이 되어버린다. 그래서 다른 곡으로 넘어가지지 않는다.
=> 인덱스가 0보다 작아지면 맨마지막 곡으로 이동하게 한다.

다음 곡으로 이동할 때도 마찬가지로 마지막 인덱스보다 더 커지면 넘어가지지 않고... 맨 첫곡 즉, 인덱스가 0인 곡으로 이동한다.

ProgressBar & Time update

function updateProgressBar(e) {
    if (isPlaying) {
        const { duration, currentTime } = e.srcElement;
        // 프로그래스바 너비 조정
        const progressPercent = (currentTime / duration) * 100;
        progress.style.width = `${progressPercent}%`;
        // 음악 duration이 보여지도록 계산
        const durationMinutes = Math.floor(duration / 60);
        let durationSeconds = Math.floor(duration % 60);
        if (durationSeconds < 10) {
            durationSeconds = `0${durationSeconds}`;
        }

        // 딜레이 시간에 텍스트가 NaN라고 뜨는 것을 방지
        if (durationSeconds) {
            durationEl.textContent = `${durationMinutes}:${durationSeconds}`;
        }
        // 현재시간을 계산해서 보여준다
        const currentMinutes = Math.floor(currentTime / 60);
        let currentSeconds = Math.floor(currentTime % 60);
        if (currentSeconds < 10) {
            currentSeconds = `0${currentSeconds}`;
        }
        currentTimeEl.textContent = `${currentMinutes}:${currentSeconds}`;
    }
}

초 부분이 10초보다 작으면 앞에 0을 붙여줌.

그리고 분:초 이런식으로 표현될 수 있도록 함.

다음 곡이나 이전 곡으로 넘길 때? 즉 딜레이가 생길 때 분:초가 뜨는 것이 아니라 NaN이 표시됨.. 그래서 분:초가 표시되도록 함.

Set progressBar

// 프로그래스바 세팅
function setProgressBar(e) {
    // 전체 길이
    const width = this.clientWidth;
    const clickX = e.offsetX;
    const { duration } = music;
    music.currentTime = (clickX / width) * duration;
}

프로그래바에서 원하는 부분 클릭하면 그 지점으로 갈 수 있도록!!

Event Listeners

// 이벤트 리스너
prevBtn.addEventListener('click', prevSong);
nextBtn.addEventListener('click', nextSong);
music.addEventListener('ended', nextSong);
music.addEventListener('timeupdate', updateProgressBar);
progressContainer.addEventListener('click', setProgressBar);

0개의 댓글