<div class="c-containter">
<div class="music-container">
<section class="album-cover">
<button class="arrow left" id="prev">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/arrow_left.svg" alt="Next Music">
</button>
<img src="//cdn.atrera.com/images/cover_yz2mak.jpg" class="cover" alt="From One To Nine by Marcel Pequel">
<button class="arrow right" id="next">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/arrow_right.svg" alt="Next Music">
</button>
</section>
<section class="music-player">
<h1 class="music-player__title"></h1>
<h2 class="music-player__author"></h2>
<div class="music-time">
<p class="music-time__current"></p>
<p class="music-time__last"></p>
</div>
<div class="music-bar" id="progress">
<div id="length"></div>
</div>
<div class="music-order">
<div class="music-order__loop is-loop" id="loop">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg" alt="Loop music">
</div>
<div class="music-order__shuffle" id="shuffle">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/shuffle.svg" alt="Shuffle music">
</div>
</div>
<div class="music-control">
<div class="music-control__backward" id="backward">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/backward.svg" alt="Backward">
</div>
<div class="music-control__play" id="play">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg" alt="Play" class="play">
</div>
<div class="music-control__forward" id="forward">
<img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/forward.svg" alt="Forward">
</div>
</div>
</section>
</div>
<p class="disclaimer">Music by Marcel Pequel and audio from <a href="http://freemusicarchive.org/music/Marcel_Pequel/From_One_To_Nine/" target="_blank" rel="noopener">Free Music Archive</a>. Design idea from <a href="https://dribbble.com/shots/2315906-Music-player-PSD-freebie-dailyui-Day-009" target="_blank" rel="noopener">Dima Blover</a></p>
</div>
$bg-1: #FFCDD2
$bg-2: #B2EBF2
$music-bar: #2196F3
$music-bar-bg: #efefef
%player-action
transition: 300ms
&:hover
opacity: 0.7
cursor: pointer
div
box-sizing: border-box
img
width: 100%
height: 100%
p
margin-top: 0
margin-bottom: 0.3em
body
font-family: 'Mukta', sans-serif
width: 100%
height: 100%
margin: 0
padding: 0
min-width: 100vw
min-height: 100vh
background: linear-gradient(-45deg, $bg-1 50%, $bg-2 50%)
//for all buttons
div > img
@extend %player-action
div,
section
box-sizing: border-box
.c-containter
display: flex
flex-flow: column nowrap
justify-content: center
align-items: center
width: 100%
height: 100vh
padding: 1em
.music-container
position: relative
display: flex
box-shadow: 1px 1px 5px 0 rgba(0,0,0,0.3)
max-height: 290px
.album-cover
flex: 1 0 30%
img
width: 100%
height: 100%
.arrow
position: absolute
top: calc(50% - 2.5em)
background: rgba(255,255,255,0.3)
border: 0
width: 5em
height: 5em
cursor: pointer
&:hover
background: rgba(255,255,255,0.5)
img
display: block
width: 20px
margin: 0 auto
&.left
left: -5em
&.right
right: -5em
.music-player
display: flex
flex-flow: column wrap
justify-content: center
background: white
padding: 1em
text-align: center
width: 500px
max-width: 500px
&__title
margin: 0 0 0.1em 0
&__author
margin: 0 0 0.5em 0
.music-bar
background: $music-bar-bg
stroke-width: 1
height: 8px
width: 100%
&:hover
cursor: pointer
#length
width: 0%
background: $music-bar
height: 100%
transition: width linear 200ms
.music-time
display: flex
flex-flow: row wrap
&__last
margin-left: auto
.music-order
display: flex
flex-flow: row wrap
&__shuffle,
&__loop
width: 1.2em
height: 1.2em
opacity: 0.2
margin: 0.3em 0
&.is-loop
opacity: 1 !important
&.is-loop-one
opacity: 1 !important
&__shuffle
margin-left: auto
.music-control
display: flex
flex-flow: row wrap
justify-content: center
align-items: center
height: 2em
&__play
width: 3em
height: 3em
margin: 0 1em
&__backward,
&__forward
width: 1.5em
height: 1.5em
.disclaimer
font-size: 0.9em
margin-top: 1em
text-align: center
a
color: $music-bar
@media all and (max-width: 960px)
.c-containter
display: block
overflow: auto
.music-container
flex-flow: column wrap
max-height: inherit
max-width: 270px
margin: 0 auto
overflow: auto
.music-player
width: 100%
max-width: 100%
&__title
font-size: 1.5em
&__author
font-size: 1em
.album-cover
position: relative
flex: 1 1 100%
max-width: 270px
max-height: 270px
.arrow
position: absolute
top: calc(50% - 1.5em)
width: 3em
height: 3em
&.left
left: 0
&.right
right: 0
.music-control
&__play
width: 2.2em
height: 2.2em
View Compiled
(function IIFE() {
const list = [
{
id: 1,
url:
"//cdn.atrera.com/audio/Marcel_Pequel_-_01_-_One.mp3",
author: "Marcel Pequel",
title: "One",
cover:
"//cdn.atrera.com/images/cover_yz2mak.jpg"
},
{
id: 2,
url:
"//cdn.atrera.com/audio/Marcel_Pequel_-_02_-_Two.mp3",
author: "Marcel Pequel",
title: "Two",
cover:
"//cdn.atrera.com/images/cover_yz2mak.jpg"
},
{
id: 3,
url:
"//cdn.atrera.com/audio/Marcel_Pequel_-_03_-_Three.mp3",
author: "Marcel Pequel",
title: "Three",
cover:
"//cdn.atrera.com/images/cover_yz2mak.jpg"
}
];
let currentId = 0;
let isPlaying = false;
let isLoop = true;
let isShuffle = false;
let currentAudio = "music1";
let timer = null;
let loopOne = false;
const currentTimeIndicator = document.querySelector(".music-time__current");
const leftTimeIndicator = document.querySelector(".music-time__last");
const progressBar = document.getElementById("length");
const playBtn = document.querySelector(".play");
const cover = document.querySelector(".cover");
const title = document.querySelector(".music-player__title");
const author = document.querySelector(".music-player__author");
const loopBtn = document.getElementById("loop");
const shuffleBtn = document.getElementById("shuffle");
const forwardBtn = document.getElementById("forward");
const backwardBtn = document.getElementById("backward");
const prevBtn = document.getElementById("prev");
const nextBtn = document.getElementById("next");
const progressDiv = document.getElementById("progress");
function play(e) {
if (!isPlaying) {
// console.log('play');
e.target.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/pause.svg";
e.target.alt = "Pause";
isPlaying = true;
document.getElementById(currentAudio).play();
showTime();
} else {
// console.log('pause');
e.target.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
e.target.alt = "Play";
document.getElementById(currentAudio).pause();
isPlaying = false;
clearInterval(timer);
}
}
function changeBar() {
const audio = document.getElementById(currentAudio);
const percentage = (audio.currentTime / audio.duration).toFixed(3);
progressBar.style.transition = "";
// console.log(audio.currentTime);
//set current time
const minute = Math.floor(audio.currentTime / 60);
const second = Math.floor(audio.currentTime % 60);
const leftTime = audio.duration - audio.currentTime;
currentTimeIndicator.innerHTML =
("0" + minute).substr(-2) + ":" + ("0" + second).substr(-2);
//set left time
const leftMinute = Math.floor(leftTime / 60);
const leftSecond = Math.floor(leftTime % 60);
leftTimeIndicator.innerHTML =
("0" + leftMinute).substr(-2) + ":" + ("0" + leftSecond).substr(-2);
//set time bar
progressBar.style.width = percentage * 100 + "%";
}
function showTime() {
timer = setInterval(() => changeBar(), 500);
}
function nextMusic(mode) {
playBtn.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
playBtn.alt = "Play";
document.getElementById(currentAudio).pause();
isPlaying = false;
clearInterval(timer);
if (mode === "next") {
currentId = currentId + 1 > list.length - 1 ? 0 : currentId + 1;
init();
} else {
currentId = currentId - 1 < 0 ? list.length - 1 : currentId - 1;
init();
}
}
function shuffle(e) {
isShuffle = !isShuffle;
if (isShuffle) {
e.target.parentNode.classList.add("is-loop");
} else {
e.target.parentNode.classList.remove("is-loop");
}
}
function backward() {
const audio = document.getElementById(currentAudio);
audio.currentTime -= 5;
if (!isPlaying) {
changeBar();
}
}
function forward() {
const audio = document.getElementById(currentAudio);
audio.currentTime += 5;
if (!isPlaying) {
changeBar();
}
}
function stopMusic() {
playBtn.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
playBtn.alt = "Play";
isPlaying = false;
}
function goToNextMusic() {
let newId = currentId;
while (isShuffle && !loopOne && newId === currentId) {
newId = Math.floor(Math.random() * Math.floor(list.length - 1));
}
if (!isShuffle && !loopOne) {
currentId = currentId + 1 > list.length - 1 ? 0 : currentId + 1;
}
if (!isShuffle && loopOne) {
currentId = currentId;
}
if (isShuffle) {
currentId = newId;
}
init();
document.getElementById(currentAudio).play();
}
function loop(e) {
const audio = document.getElementById(currentAudio);
if (!isLoop && !loopOne) {
isLoop = true;
loopOne = false;
// console.log('is loop');
e.target.parentNode.classList.add("is-loop");
e.target.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg";
audio.loop = false;
audio.onended = e => goToNextMusic();
console.log(isLoop, loopOne);
} else if (isLoop && !loopOne) {
// console.log('is loop one');
isLoop = true;
loopOne = true;
e.target.parentNode.classList.add("is-loop");
e.target.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loopone.svg";
audio.loop = true;
audio.onended = e => goToNextMusic();
console.log(isLoop, loopOne);
} else {
// console.log('not loop');
isLoop = false;
loopOne = false;
e.target.parentNode.classList.remove("is-loop");
e.target.src =
"https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg";
audio.loop = false;
audio.onended = e => stopMusic();
console.log(isLoop, loopOne);
}
}
function progress(e) {
const audio = document.getElementById(currentAudio);
//get current position and minus progress bar's x position to get current position in progress bar
const pos =
(e.pageX - progressDiv.getClientRects()[0].x) /
progressDiv.getClientRects()[0].width;
audio.currentTime = pos * audio.duration;
changeBar();
}
function init() {
//reset music duration and setup audio
const audio =
document.getElementById(currentAudio) === null
? new Audio()
: document.getElementById(currentAudio);
audio.src = list[currentId].url;
audio.id = currentAudio;
document.getElementById(currentAudio) === null
? document.body.appendChild(audio)
: "";
progressBar.style.transition = "none";
progressBar.style.width = "0%";
document.getElementById(currentAudio).currentTime = 0;
title.innerHTML = list[currentId].title;
author.innerHTML = list[currentId].author;
cover.src = list[currentId].cover;
//set current time
audio.addEventListener("loadedmetadata", function() {
const leftMinute = Math.floor(audio.duration / 60);
const leftSecond = Math.floor(audio.duration % 60);
currentTimeIndicator.innerHTML = "00:00";
leftTimeIndicator.innerHTML =
("0" + leftMinute).substr(-2) + ":" + ("0" + leftSecond).substr(-2);
progressBar.style.transition = "";
});
//set loop
document.getElementById(currentAudio).onended = e => goToNextMusic(e);
}
playBtn.addEventListener("click", play);
loopBtn.addEventListener("click", loop);
shuffleBtn.addEventListener("click", shuffle);
forwardBtn.addEventListener("click", forward);
backwardBtn.addEventListener("click", backward);
prevBtn.addEventListener("click", e => nextMusic("prev"));
nextBtn.addEventListener("click", e => nextMusic("next"));
progressDiv.addEventListener("click", e => {
progress(e);
});
init();
})();
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.