HTML, CSS, JavaScript를 사용해 음악 플레이어를 만들어보았습니다.
이 플레이어는
노래 정보 표시, 재생/일시정지, 이전/다음 곡으로 넘어가기, 진행 바 등
기본적인 음악 플레이어 기능을 구현합니다.
1. HTML 구조
우선, HTML 파일을 작성합니다. 음악 플레이어의 기본 구조는 다음과 같습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Music Player | Codesign</title>
</head>
<body>
<div class="container">
<div class="song-info">
<div class="song-name">Song</div>
<div class="artist-name">Artist</div>
<div class="progress-bar">
<div class="fill-bar"></div>
</div>
<div class="song-time">
<div class="start-time">0:00</div>
<div class="end-time">0:00</div>
</div>
</div>
<div class="disk">
<div class="circle"></div>
<div id="cover" class="cover"></div>
</div>
<div class="controls">
<img width="20" height="20" src="https://img.icons8.com/material-outlined/48/repeat.png" alt="repeat"/>
<img width="20" height="20" id="prev" src="https://img.icons8.com/ios-glyphs/90/rewind.png" alt="rewind"/>
<img width="20" height="20" id="play" src="https://img.icons8.com/ios-glyphs/90/play--v1.png" alt="play--v1"/>
<img width="20" height="20" id="next" src="https://img.icons8.com/ios-glyphs/90/fast-forward.png" alt="fast-forward"/>
<img width="20" height="20" src="https://img.icons8.com/fluency-systems-regular/48/video-playlist.png" alt="video-playlist"/>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
- container: 전체 플레이어를 감싸는 컨테이너입니다.
- song-info: 노래 이름, 아티스트 이름, 진행 바 및 시간을 표시합니다.
- disk: 앨범 커버 이미지를 표시합니다.
- controls: 재생, 이전, 다음, 반복 버튼이 위치해 있습니다.
2. CSS 스타일링
style.css 파일을 통해 플레이어의 스타일을 지정합니다.
* {
margin: 0;
padding: 0;
}
body {
background-color: #F4F6FF;
box-sizing: border-box;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
position: relative;
width: 400px;
background: linear-gradient(#FEA3A3, #BFD1FF);
padding: 60px 20px;
border-radius: 30px;
}
.container .song-info {
margin: 0 15px;
padding: 220px 15px 45px;
}
.container .song-info .song-name {
display: flex;
justify-content: center;
font-size: 15px;
}
.container .song-info .artist-name {
display: flex;
justify-content: center;
font-size: 12px;
margin: 10px 0 30px;
}
.container .song-info .progress-bar {
background: linear-gradient(to right, #FFA8A8, #C48EFF);
border-radius: 20px;
cursor: pointer;
}
.container .song-info .progress-bar .fill-bar {
width: 0;
height: 6px;
border-radius: 20px;
background-color: #fff;
}
.container .song-info .song-time {
display: flex;
justify-content: space-between;
}
.container .song-info .start-time,
.container .song-info .end-time {
font-size: 12px;
color: #828282;
margin: 10px 0;
}
.container .disk {
max-width: 120px;
}
.container .disk .active {
animation: rotate 3s linear 0s infinite forwards;
}
.container .disk .cover {
width: 200px;
height: 200px;
position: absolute;
top: 37px;
left: 113px;
background: url("assets/1.jpg");
background-repeat: no-repeat;
background-position: bottom center;
background-size: cover;
border: 5px solid #fff;
border-radius: 50%;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease-in-out;
}
.container .disk .circle {
position: absolute;
width: 22px;
height: 22px;
left: 47%;
top: 23%;
background-color: #fff;
z-index: 1;
border-radius: 50%;
}
.container .controls {
display: flex;
align-items: center;
justify-content: center;
gap: 40px;
}
.container .controls #play {
background-color: hsl(239, 100%, 80%);
padding: 15px;
border-radius: 50%;
transition: all 0.3s ease;
}
.container .controls #play:hover {
background: #7375ff;
}
.controls img {
cursor: pointer;
}
@keyframes rotate {
0% {
transform: rotateX(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
- container: 전체 레이아웃을 구성하며, 그림자 효과와 둥근 모서리를 부여했습니다.
- progress-bar 및 fill-bar: 진행 바와 채워지는 부분을 스타일링했습니다.
3. JavaScript로 기능 구현
다음으로, script.js 파일을 통해 플레이어의 기능을 구현합니다.
const songsList = [
{
name: "Lost in Your Eyes",
artist: "TFLM",
src: "assets/1.mp3",
cover: "assets/1.jpg"
},
{
name: "All Night",
artist: "Ikson",
src: "assets/2.mp3",
cover: "assets/2.jpg"
},
{
name: "Lie 2 You",
artist: "Leonell Cassio",
src: "assets/3.mp3",
cover: "assets/3.jpg"
}
]
const artistName = document.querySelector('.artist-name');
const musicName = document.querySelector('.song-name');
const fillBar = document.querySelector('.fill-bar');
const startTime = document.querySelector('.start-time');
const endTime = document.querySelector('.end-time');
const prog = document.querySelector('.progress-bar');
const cover = document.getElementById('cover');
const playBtn = document.getElementById('play');
const prevBtn = document.getElementById('prev');
const nextBtn = document.getElementById('next');
const playIcon = "https://img.icons8.com/ios-glyphs/90/play--v1.png";
const pauseIcon = "https://img.icons8.com/ios-filled/50/pause--v1.png";
let song = new Audio();
let currentSong = 0;
let playing = false;
document.addEventListener('DOMContentLoaded', () => {
loadSong(currentSong);
song.addEventListener('timeupdate', updateProgress);
song.addEventListener('ended', nextSong);
prevBtn.addEventListener('click',prevSong);
nextBtn.addEventListener('click', nextSong);
playBtn.addEventListener('click',togglePlayPause);
prog.addEventListener('click',seek);
})
function loadSong(index) {
const { name, artist, src, cover: thumb } = songsList[index];
artistName.innerText = artist;
musicName.innerText = name;
song.src = src;
cover.style.backgroundImage = `url(${thumb})`;
}
function updateProgress() {
if (song.duration) {
const pos = (song.currentTime / song.duration) * 100;
fillBar.style.width = `${pos}%`;
startTime.innerText = formatTime(song.currentTime);
endTime.innerText = formatTime(song.duration);
}
}
function formatTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${minutes}:${secs < 10 ? '0' : ''}${secs}`
}
function updatePlayButton() {
playBtn.src = playing ? pauseIcon : playIcon;
playBtn.alt = playing ? "pause--v1" : "play--v1";
playBtn.id = "play";
}
function togglePlayPause() {
playing ? song.pause() : song.play();
playing = !playing;
updatePlayButton();
cover.classList.toggle('active', playing);
}
function nextSong() {
currentSong = (currentSong + 1) % songsList.length;
playMusic();
}
function prevSong() {
currentSong = (currentSong -1 + songsList.length) % songsList.length;
playMusic();
}
function playMusic() {
loadSong(currentSong);
song.play();
playing = true;
updatePlayButton();
cover.classList.add('active');
}
function seek(e) {
const pos = (e.offsetX / prog.clientWidth) * song.duration;
song.currentTime = pos;
}
'프론트엔드 > JavaScript' 카테고리의 다른 글
[ JavaScript ] findIndex와 indexOf의 차이점 알아보기 (0) | 2024.10.17 |
---|---|
[ Javascript ] Drop Down(드롭다운) 메뉴 만들기 (0) | 2024.04.23 |
[ JavaScript ] Class 초기값 설정해주기, 상속 하기 (0) | 2022.12.05 |
[ JavaScript ] currentTarget vs target 차이점 (0) | 2022.11.17 |
[ JavaScript ] ES6의 화살표 함수 (0) | 2022.10.23 |
댓글