<!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>
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');
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: '제로',
},
];
// 실행되고 있는 지 확인
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로 바꿔준다.
// 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과 이미지를 불러온다.
// 현재 곡
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인 곡으로 이동한다.
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이 표시됨.. 그래서 분:초가 표시되도록 함.
// 프로그래스바 세팅
function setProgressBar(e) {
// 전체 길이
const width = this.clientWidth;
const clickX = e.offsetX;
const { duration } = music;
music.currentTime = (clickX / width) * duration;
}
프로그래바에서 원하는 부분 클릭하면 그 지점으로 갈 수 있도록!!
// 이벤트 리스너
prevBtn.addEventListener('click', prevSong);
nextBtn.addEventListener('click', nextSong);
music.addEventListener('ended', nextSong);
music.addEventListener('timeupdate', updateProgressBar);
progressContainer.addEventListener('click', setProgressBar);