Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Preface
The other day when I listened to five people, the combination of female vocals and band always gave me a feeling of double vision. Think of a nanjing citizen, those senior three every day to listen to the song.
So I decided to write a full platform can listen to the online player, also save the download.
Pieced together you big guy code whole a still fairly comfortable player, using Vue2.6, there are more than 200 songs, random play, is the kind of radio feeling, I hope you like π
Github. IO and Codepen
The source code can be seen here: Github
HTML
The overall framework
Basically refer to π€‘
<div class="wrapper" id="app">
<div class="player">
<div class="player__top">
<! -- Cover, Pause/Play, Previous track, next track, β€, π Five buttons -->
</div>
<div class="progress" ref="progress">
<! -- Progress bar, song information, current playing time, total playing time -->
</div>
</div>
</div>
Copy the code
Buttons are drawn in SVG and path is omitted here.
All online, direct copy source code Github
<svg xmlns="http://www.w3.org/2000/svg" hidden xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<! -- Hollow and solid β€ -->
<symbol id="icon-heart-o" viewBox="0 0 32 32">
<title>icon-heart-o</title>
</symbol>
<symbol id="icon-heart" viewBox="0 0 32 32">
<title>icon-heart</title>
</symbol>
<! -- Pause and play buttons -->
<symbol id="icon-pause" viewBox="0 0 32 32">
<title>icon-pause</title>
</symbol>
<symbol id="icon-play" viewBox="0 0 32 32">
<title>icon-play</title>
</symbol>
<! -- Link button π -->
<symbol id="icon-link" viewBox="0 0 32 32">
<title>link</title>
</symbol>
<! -- The last and the next -->
<symbol id="icon-next" viewBox="0 0 32 32">
<title>next</title>
</symbol>
<symbol id="icon-prev" viewBox="0 0 32 32">
<title>prev</title>
</symbol>
</defs>
</svg>
Copy the code
Album cover
<div class="player-cover">
<transition-group :name="transitionName">
<div class="player-cover__item" v-if="$index === currentTrackIndex"
:style="{ backgroundImage: `url(${track.cover})` }"
v-for="(track, $index) in tracks" :key="$index">
</div>
</transition-group>
</div>
Copy the code
Play & Pause
<div class="player-controls__item -xl js-play" @click="play">
<svg class="icon">
<use xlink:href="#icon-pause" v-if="isTimerPlaying"></use>
<use xlink:href="#icon-play" v-else></use>
</svg>
</div>
Copy the code
Last one & next one
<div class="player-controls__item" @click="prevTrack">
<svg class="icon">
<use xlink:href="#icon-prev"></use>
</svg>
</div>
<div class="player-controls__item" @click="nextTrack">
<svg class="icon">
<use xlink:href="#icon-next"></use>
</svg>
</div>
Copy the code
β€ π
<div class="player-controls__item -favorite"
:class="{ active : currentTrack.favorited }"
@click="favorite">
<svg class="icon">
<use xlink:href="#icon-heart-o"></use>
</svg>
</div>
<a :href="currentTrack.url" target="_blank" class="player-controls__item">
<svg class="icon">
<use xlink:href="#icon-link"></use>
</svg>
</a>
Copy the code
Song info & Progress bar
<div class="progress" ref="progress">
<div class="progress__top">
<div class="album-info" v-if="currentTrack">
<div class="album-info__name">{{ currentTrack.artist }}</div>
<div class="album-info__track">{{ currentTrack.name }}</div>
</div>
<div class="progress__duration">{{ duration }}</div>
</div>
<div class="progress__bar" @click="clickProgress">
<div class="progress__current" :style="{ width : barWidth }"></div>
</div>
<div class="progress__time">{{ currentTime }}</div>
</div>
<div v-cloak></div>
Copy the code
CSS
The key point is the adaptation of @media, nothing to say, just put a little code, want to see Github it.
body {
background: #dfe7ef;
font-family: "Bitter", serif; {} *box-sizing: border-box;
}
.icon {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
}
.wrapper {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-size: cover;
@media screen and (max-width: 700px), (max-height: 500px) {
flex-wrap: wrap;
flex-direction: column; }}Copy the code
Vue
Import Github audio source and Vue:
<script src="https://cdn.jsdelivr.net/gh/nj-lizhi/song@master/audio/list.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
Copy the code
The overall framework
new Vue({
el: "#app".data() {
return {
audio: null.circleLeft: null.barWidth: null.duration: null.currentTime: null.isTimerPlaying: false.tracks: list, // Import the audio source
currentTrack: null.currentTrackIndex: 0.transitionName: null
};
},
methods: {
play() {
// Play & pause
},
generateTime() {
/ / the length
},
updateBar(x) {
/ / the progress bar
},
clickProgress(e) {
// Click the progress bar to adjust progress
},
prevTrack() {
/ / a
},
nextTrack() {
/ / a
},
resetPlayer() {
/ / reset
},
favorite() {
/ / β€}},created() {
let vm = this;
// The first song is "suddenly"
this.currentTrack = this.tracks[3];
this.audio = new Audio();
this.audio.src = this.currentTrack.url;
this.audio.ontimeupdate = function () {
vm.generateTime();
};
this.audio.onloadedmetadata = function () {
vm.generateTime();
};
// Switch to the next track automatically
this.audio.onended = function () {
vm.nextTrack();
this.isTimerPlaying = true; }; }});Copy the code
Play & Pause
play() {
if (this.audio.paused) {
this.audio.play();
this.isTimerPlaying = true;
} else {
this.audio.pause();
this.isTimerPlaying = false; }},Copy the code
The length
generateTime() {
let width = (100 / this.audio.duration) * this.audio.currentTime;
this.barWidth = width + "%";
this.circleLeft = width + "%";
let durmin = Math.floor(this.audio.duration / 60);
let dursec = Math.floor(this.audio.duration - durmin * 60);
let curmin = Math.floor(this.audio.currentTime / 60);
let cursec = Math.floor(this.audio.currentTime - curmin * 60);
if (durmin < 10) {
durmin = "0" + durmin;
}
if (dursec < 10) {
dursec = "0" + dursec;
}
if (curmin < 10) {
curmin = "0" + curmin;
}
if (cursec < 10) {
cursec = "0" + cursec;
}
this.duration = durmin + ":" + dursec;
this.currentTime = curmin + ":" + cursec;
},
Copy the code
The progress bar
updateBar(x) {
let progress = this.$refs.progress;
let maxduration = this.audio.duration;
let position = x - progress.offsetLeft;
let percentage = (100 * position) / progress.offsetWidth;
if (percentage > 100) {
percentage = 100;
}
if (percentage < 0) {
percentage = 0;
}
this.barWidth = percentage + "%";
this.circleLeft = percentage + "%";
this.audio.currentTime = (maxduration * percentage) / 100;
this.audio.play();
},
Copy the code
Click the progress bar to adjust the progress
clickProgress(e) {
this.isTimerPlaying = true;
this.audio.pause();
this.updateBar(e.pageX);
},
Copy the code
Last one & next one
The way I set it up is that the next song will play randomly and the last one will play π in order
prevTrack() {
this.transitionName = "scale-in";
if (this.currentTrackIndex > 0) {
this.currentTrackIndex--;
} else {
this.currentTrackIndex = this.tracks.length - 1;
}
this.currentTrack = this.tracks[this.currentTrackIndex];
this.resetPlayer();
},
nextTrack() {
this.transitionName = "scale-out";
this.currentTrackIndex = parseInt(this.tracks.length * Math.random());
this.currentTrack = this.tracks[this.currentTrackIndex];
this.resetPlayer();
},
Copy the code
reset
Reset every time you cut:
resetPlayer() {
this.barWidth = 0;
this.circleLeft = 0;
this.audio.currentTime = 0;
this.audio.src = this.currentTrack.url;
setTimeout(() = > {
if (this.isTimerPlaying) {
this.audio.play();
} else {
this.audio.pause(); }},300);
},
Copy the code
β€
The function of the red heart was abandoned, because it is the big guy to arrange the sound source without relevant items, and this function is more chicken ribs, no memory, β fell out.
favorite() {
this.tracks[this.currentTrackIndex].favorited = !this.tracks[
this.currentTrackIndex
].favorited;
}
Copy the code
Todo
There are still some features to be done when I have time π :
- Diablo mode
- Single cycle, list cycle, list sequence play several play modes
- List shows all songs
- …
Summary
I may be a vegetable dog, but I still got him. This is standing on the shoulders of predecessors, love love!
β€ Thank the following open source projects:
-
GoldSubmarine/lizhi
-
nj-lizhi/song
-
Mini Music Player
If it is helpful to you, I hope I can give π comment collection three even!
Welcome to pay attention to exchange, have a question can comment message.
I am Mancuoj, more interesting articles: Mancuoj personal homepage