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 😛 :

  1. Diablo mode
  2. Single cycle, list cycle, list sequence play several play modes
  3. 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