유데미에서 Brad Traversy의 20 Web Projects With Vanilla JavaScript
를 하나씩 직접 코딩해보면서 정리하기 위한 글이다.
데모 페이지
vanillawebprojects.com/projects/music-player/
코드 링크
github.com/rshak8912/20-Web-Projects
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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">
<title>Music Player</title>
</head>
<body>
<h1>뮤직 플레이어</h1>
<div class="music-container" id="music-container">
<div class="music-info">
<h4 id="title">ukulele</h4>
<div class="progress-container" id="progress-container">
<div class="progress" id="progress"></div>
</div>
</div>
<audio src="music/ukulele.mp3" id="audio"></audio>
<div class="img-container">
<img src="images/ukulele.jpg" alt="music-cover" id="cover">
</div>
<div class="navigation">
<button id="prev" class="action-btn">
<i class="fas fa-backward"></i>
</button>
<button id="play" class="action-btn action-btn-big">
<i class="fas fa-play"></i>
</button>
<button id="next" class="action-btn">
<i class="fas fa-forward"></i>
</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
style.css
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
* {
box-sizing: border-box;
}
body {
background-image: linear-gradient(
0deg,
rgba(247, 247, 247, 1) 23.8%,
rgba(252, 221, 221, 1) 92%
);
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Lato', sans-serif;
margin: 0;
}
.music-container {
background-color: #ffffff;
border-radius: 15px;
box-shadow: 0 20px 20px 0 rgba(252, 169, 169, 0.6);
display: flex;
padding: 20px 30px;
position: relative;
margin: 100px 0;
z-index: 10;
}
.img-container::after {
content: '';
background-color: #fff;
border-radius: 50%;
position: absolute;
bottom: 100%;
left: 50%;
width: 20px;
height: 20px;
transform: translate(-50%, 50%);
}
.img-container {
position: relative;
width: 110px;
}
.img-container img {
border-radius: 50%;
object-fit: cover;
height: 110px;
width: inherit;
position: absolute;
bottom: 0;
left: 0;
animation: rotate 3s linear infinite;
animation-play-state: paused;
}
.music-container.play .img-container img {
animation-play-state: running;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.action-btn {
background-color: #fff;
border: 0;
color: #dfdbdf;
font-size: 20px;
cursor: pointer;
padding: 10px;
margin: 0 20px;
}
.action-btn.action-btn-big {
color: #cdc2d0;
font-size: 30px;
}
.action-btn:focus {
outline: 0;
}
.music-info {
background-color: rgba(255, 255, 255, 0.5);
border-radius: 15px 15px 0 0;
position: absolute;
top: 0;
left: 20px;
width: calc(100% - 40px);
padding: 10px 10px 10px 150px;
opacity: 0;
transform: translateY(0%);
transition: transform 0.3s ease-in, opacity 0.3s ease-in;
z-index: 0;
}
.music-container.play .music-info {
opacity: 1;
transform: translateY(-100%);
}
.music-info h4 {
margin: 0;
}
.progress-container {
background: #ffffff;
border-radius: 5px;
cursor: pointer;
margin: 10px 0;
height: 4px;
width: 100%;
}
.progress {
background-color: #fe8daa;
border-radius: 5px;
height: 100%;
width: 40%;
transition: width 0.1s linear;
}
script.js
const musicContainer = document.getElementById('music-container');
const playBtn = document.getElementById('play');
const prevBtn = document.getElementById('prev');
const nextBtn = document.getElementById('next');
const audio = document.getElementById('audio');
const progress = document.getElementById('progress');
const progressContainer = document.getElementById('progress-container');
const title = document.getElementById('title');
const cover = document.getElementById('cover');
const songs = ['hey', 'summer', 'ukulele'];
let songIndex = 2;
loadSong(songs[songIndex]);
function loadSong(song) {
title.innerText = song;
audio.src = `music/${song}.mp3`;
cover.src = `images/${song}.jpg`;
}
function playSong() {
musicContainer.classList.add('play');
playBtn.querySelector('i.fas').classList.remove('fa-play');
playBtn.querySelector('i.fas').classList.add('fa-pause');
audio.play();
}
function pauseSong() {
musicContainer.classList.remove('play');
playBtn.querySelector('i.fas').classList.add('fa-play');
playBtn.querySelector('i.fas').classList.remove('fa-pause');
audio.pause();
}
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();
}
function updateProgress(e) {
const { duration, currentTime } = e.srcElement;
const progressPercent = (currentTime / duration) * 100;
progress.style.width = `${progressPercent}%`;
}
function setProgress(e) {
const width = this.clientWidth;
const clickX = e.offsetX;
const duration = audio.duration;
audio.currentTime = (clickX / width) * duration;
}
// Event listeners
playBtn.addEventListener('click', () => {
const isPlaying = musicContainer.classList.contains('play');
if (isPlaying) {
pauseSong();
} else {
playSong();
}
});
prevBtn.addEventListener('click', prevSong);
nextBtn.addEventListener('click', nextSong);
// Time/song update
audio.addEventListener('timeupdate', updateProgress);
// Click on progress bar
progressContainer.addEventListener('click', setProgress);
// Song ends
audio.addEventListener('ended', nextSong);
강의를 통해 배운 점(생각, 내용 정리)
- 오디오 태그를 사용한 음악 파일 재생법과 스탑, 퍼즈, 플레이 등의 기능 구현을 해볼 수 있었음.
'HTML&CSS&Javascript' 카테고리의 다른 글
[Udemy]20 Web Projects With Vanilla JavaScript -Project#12 (0) | 2020.12.30 |
---|---|
[Udemy]20 Web Projects With Vanilla JavaScript -Project#11 (0) | 2020.12.30 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#9 (0) | 2020.12.29 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#8 (0) | 2020.12.13 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#7 (0) | 2020.12.11 |