用Vue搭建一个运用盒子(三):音乐播放器

这个播放器的开辟用时2个多月,并非说它有多庞杂,相反它的功用还异常不完美,仅具雏形。之所以磨磨蹭蹭这么久,一是因为迁延,二也是练习公司项目太紧。8月尾完毕练习前写完了款式,以后在家余暇时刻多了,集中精力就把JS部份做完了。

这个播放器确切比当初设想的庞杂,最先只盘算做一个搜歌播放的功用。如今做出来的这个播放器,可以猎取热点歌曲,可以搜歌,可以调解播放进度条,功用确切完美不少。

此次完成这个项目也是收成颇丰,点了不少新的妙技点,固然,这个大略的小项目也挖了不少坑,不知道啥时刻能填上……

话不多说,看代码吧。

Muse-ui

不记得在哪一个网站看到这个组件库的了,以为好酷炫,因而用起来~

这是官网:地点

运用这个组件库的缘由除了美丽,还因为这是基于Vue 2.0,无缝对接,轻易。

运用要领跟之前的插件一样,npm装置:

npm install --save muse-ui

装置好后,在main.js中注册。

import MuseUi from 'muse-ui'
import 'muse-ui/dist/muse-ui.css'
import 'muse-ui/dist/theme-light.css'

Vue.use(MuseUi)

就可以在项目中运用了。
PS:Muse-ui的icon是基于谷歌的Material icons,人人可以依据本身的需求到官网找icon的代码。

组件构造

接着我们就该搭建这个播放器的组件了。

构造以下:

||-- player.vue       // 主页面
|    |-- playerBox.vue   // 播放器组件
|    |-- popular.vue    // 热点歌曲页面
|        |-- songList.vue     // 歌曲列表页面 
|    |-- play.vue    // 播放器页面
|    |-- search.vue    // 搜刮页面

PS:热点歌曲、搜刮页面都能进入歌曲列表页面,播放器组件playerBox.vue 是放<audio>标签的组件,是功用性组件。

我们来离别叙说:

1.player.vue

直接看代码吧:

<template>
  <div class="player">

    <!-- banner here-->
    <router-view></router-view>

    <!-- navbar here -->
    <mu-paper>
      <mu-bottom-nav :value="bottomNav" @change="handleChange">
        <mu-bottom-nav-item value="popular" title="盛行" icon="music_note" to="/popular"/>
        <mu-bottom-nav-item value="play" title="播放" icon="play_arrow" to="/play"/>
        <mu-bottom-nav-item value="search" title="搜刮" icon="search" to="/search"/>
      </mu-bottom-nav>
    </mu-paper>

    <!-- html5 player here -->
    <playerBox></playerBox>

  </div>
</template>

<script>

import playerBox from './playerBox.vue'

export default {



  name: 'player',
  data(){
    const pa=this.$route.path;
    const Pa=pa.slice(1);

    return{
      bottomNav: Pa
    }
  },
  components: {
    playerBox
  },
  methods:{
    handleChange (val) {
      this.bottomNav = val
    },
    changebar(){
      const va=this.$route.path;
      const Va=va.slice(1);
      this.bottomNav = Va
    }
  },
  watch:{
    "$route":"changebar"
  }
}
</script>
  

<style lang="less" >
  .mu-bottom-nav{
    position: fixed!important;
    bottom: 0px;
    background: #fafafa!important;
    z-index: 5;
    
  }
</style>

诠释一下:

  1. 因为Muse-ui有部份款式用到了less,所以在这里我们须要npm装置一个less的依靠,装置好后即可运用。

npm install less less-loader --save

  1. 这里我们加载了一个底部导航,muse-ui的,官网可以查到相干代码。这里要注重的是,为了让用户体验更好,我们须要让我们的底部导航随当前路由变化而高亮。详细是用了一段JS代码。

watch看管路由变化并触发一个method:changebar(),这个函数会猎取当前的路由名,并把bottomNav的值设置为当前路由名——即高亮当前的路由页面

  1. playerBox.vue组件之所以放在主组件里,就是为了音乐在每个子页面都能播放,而不会因为跳转路由而住手播放。

2.popular.vue

这是引荐歌单界面,这里用到了一个轮播图插件,是基于vue的,运用起来比较轻易,直接用npm装置:

npm install vue-awesome-swiper --save

装置好后,一样在main.js中注册:

import VueAwesomeSwiper from 'vue-awesome-swiper'

Vue.use(VueAwesomeSwiper)

然后我们来看页面的代码:

<template>
  <div class="popular">

    <!-- navbar here -->
    <mu-appbar>
      <div class="logo">
        iPlayer
      </div>
    </mu-appbar>

    <!-- banner here-->
    <mu-card>
        <swiper :options="swiperOption">
          <swiper-slide v-for="(item,index) in banners" :key="index">
            <mu-card-media>
              <img :src="item.pic">
            </mu-card-media>
          </swiper-slide>
          <div class="swiper-pagination" slot="pagination"></div>
        </swiper>
    </mu-card>
    
    <div class="gridlist-demo-container" >
      <mu-grid-list class="gridlist-demo">
        <mu-sub-header>热点歌单</mu-sub-header>
           <mu-grid-tile v-for="(item, index) in list" :key="index">
            <img :src="item.coverImgUrl"/>
            <span slot="title">{{item.name}}</span>
            <mu-icon-button icon="play_arrow" slot="action" @click="getListDetail(item.id)"/>
         </mu-grid-tile>
      </mu-grid-list>
    </div>
    
    <div class="footer-rights">
      <h4>版权归Godown Huang一切,请<a href="https://github.com/WE2008311">联络我</a>。</h4>
    </div>


  </div>
</template>

<script>
import {swiper,swiperSlide} from 'vue-awesome-swiper'
import axios from 'axios'

export default {

  name: 'popular',
  data(){
    return{
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationClickable: true,
        autoplay: 4000,
        loop:true
      },
      banners:[],
      list: []
    }
  },
  components: {
    swiper,
    swiperSlide
  },
  computed:{
    
  },
  created(){
    this.initPopular()
    
  },
  methods:{
    initPopular(){
      
      axios.get('http://localhost:3000/banner').then(res=> {
             this.banners=res.data.banners;
      }),
      axios.get('http://localhost:3000/top/playlist/highquality?limit=8').then(res=> {
             this.list=res.data.playlists;
      })
    },
    getListDetail(id){
      this.$router.push({path: '/songsList'})
      this.$store.commit('playlist',id);
    }
  }
}
</script>
  

<style lang="css">
  @media screen and (min-width: 960px){
    .mu-card-media>img{
      height: 400px!important;
    }
    .mu-grid-list>div:nth-child(n+2){
      width:25%!important;
    }
  }

  .mu-grid-tile>img{
    width: 100%;
  }

  .gridlist-demo-container{
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
  
  .gridlist-demo{
    width: 100%;
    overflow-y: auto;
  }
  .footer-rights>h4{
    color: #e1e1e1;
    font-weight: 100;
    font-size:.056rem;
    height:90px;
    padding-top: 10px;
    text-align: center;
  }
</style>

这里要申明一下,上面的这些组件除了
playerBox以外都要在main.js中注册才运用。注册要领遗忘的了话,回头看看我之前写的todolist的项目是怎样注册的。

store.js中增加playList函数:

playlist(state,id){
        const url='http://localhost:3000/playlist/detail?id='+id;
        axios.get(url).then(res=> {
            state.playlist=res.data.playlist;
        })
    },

这里的页面mu开首的基础都是用Muse-ui搭建起来的,Swiper开首的则是轮播图插件。界面不庞杂,主假如三个部份,上面的轮播图,中心的热点歌单引荐,底部的版权信息。款式基础是模板,这里做了一个简朴的挪动端适配:在PC端歌单会以每排4个分两排的情势分列,在挪动端歌单则会以每排2个分四排的情势分列,适配的要领是媒体查询,经由过程转变歌单div的宽度转变每行歌单的数量。

这里要注重的:

  1. 歌单的数据和轮播图都是用的网易云数据,所以没有开api是没法读取的,引入axios的部份可以先不写,也可以写好先放着。
  2. 这里methodscreated内里的内容都涉及到axios的要求,所以可以先不写,不影响款式显现。数据可以先用假数据替代。
  3. playList的目标是点击歌单的时刻,进入歌单详情页,同时依据通报进去的歌单id猎取歌单的详细数据,axios的地点是api的地点,须要加载api插件才运用。

3.play.vue

终究到了最中心的组件,之所以说它中心是因为这是播放界面,音频播放的长度、音频信息都邑在这里被显现,而播放器的中心功用——播放——也是在这里被操纵(播放/停息)。

看详细代码:

<template>
  <div class="play">

    <!-- navbar here -->
    <mu-appbar>
      <mu-icon-button icon="navigate_before" slot="left" v-on:click="backpage"/>
      <div class="logo">
        iPlayer
      </div>
    </mu-appbar>

    <!-- player here-->
    <div class="bgImg">
      <img :src="audio.picUrl" />
      <!-- 封面CD -->
      <mu-avatar  slot="left" :size="300" :src="audio.picUrl"/>
    </div>
    
    <div class="controlBar">
        <mu-content-block>
          {{audio.songName}} - {{audio.singer}}
        </mu-content-block>
        <div class="controlBarSlide">
          <span class="slideTime">{{audio.currentTime}}</span>
          <mu-slider v-bind:value="progressPercent" @change="editprogress" class="demo-slider"/>
          <span class="slideTime">{{audio.duration}}</span>
        </div>
        
    </div>


  </div>
</template>

<script>


export default {
  
  name: 'play',
  data(){
    return{
      
    }
  },
  components: {
    
  },
  computed:{
      audio(){
        return this.$store.getters.audio;
      },
      progressPercent(){
        return this.$store.getters.audio.progressPercent;
      }
  },
  methods:{
    backpage(){
      window.history.go(-1);
    },
    
    editprogress(value){
      
      this.$store.commit('editProgress',value)
    }
  }
}
</script>
  

<style lang="css">
  @media screen and (max-width: 414px){
    .bgImg .mu-avatar{
      height: 260px!important;
      width: 260px!important;
      margin-left: -130px!important;
    }
  }
  .bgImg{
    position:fixed;
    height:100%;
    width:100%;
    background: #fff;
    z-index:-1;
  }
  .bgImg>img{
    width: 100%;
    filter:blur(15px);
    -webkit-filter: blur(15px); 
    -moz-filter: blur(15px);
    -ms-filter: blur(15px);
  }
  .bgImg .mu-avatar{
    position: absolute;
    left: 50%;
    margin-left: -150px;
    top: 30px;
  }
  .controlBar{
    position: fixed;
    width: 100%;
    height: 180px;
    background: #fff;
    bottom: 0;
    z-index: 11;
    text-align:center;
  }
  
  .mu-slider{
    width: 70%!important;
    display: inline-block!important;
    margin-bottom: -7px!important;
  }
  
  
  .slideTime{
    width: 29px;
    display: inline-block;
  }
  .mu-content-block{
    font-size: 18px;
    color: #777
  }
  .mu-slider{
    display: inline-block;
    margin:0 3px -7px;
    width: 70%;
  }
</style>

store.js增加代码:

 play(state){
        clearInterval(ctime);
        const playerBar=document.getElementById("playerBar");
        const eve=$('.addPlus i')[0];
        
        
        let currentTime=playerBar.currentTime;
        let currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);
        let duraTime=playerBar.duration;
        let duraMinute=Math.floor(duraTime/60)+":"+(duraTime%60/100).toFixed(2).slice(-2);
        state.audio.progressPercent=((playerBar.currentTime/playerBar.duration)*100).toFixed(1);
        
        if(playerBar.paused){
            playerBar.play();
            eve.innerHTML="pause";
            state.audio.duration=duraMinute;
            state.audio.currentTime=currentMinute;
            ctime=setInterval(
                function(){
                    
                    currentTime++;
                    
                    currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);
                    
                    state.audio.currentTime=currentMinute;
                    state.audio.progressPercent=((playerBar.currentTime/playerBar.duration)*100).toFixed(1);
                    
                },1000
            )
        }else {
            playerBar.pause();
            eve.innerHTML="play_arrow";
            clearInterval(ctime);
        }
               
        
    },

    audioEnd(state){
        
        const playerBar=document.getElementById("playerBar");
        const eve=$('.addPlus i')[0];

        eve.innerHTML="play_arrow";
        clearInterval(ctime);

        
        playerBar.currentTime=0;

        let currentTime=playerBar.currentTime;
        let currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);
        state.audio.currentTime=currentMinute;
    },

    editProgress(state,progressValue){
        const playerBar=document.getElementById("playerBar");
        const eve=$('.addPlus i')[0];

        let duraTime=playerBar.duration;
        let duraMinute=Math.floor(duraTime/60)+":"+(duraTime%60/100).toFixed(2).slice(-2);
        // console.log(progressValue);
        clearInterval(ctime);
        if(playerBar.paused){
            playerBar.play();
            eve.innerHTML="pause"
            state.audio.duration=duraMinute;
        }
        let currentTime=playerBar.duration*(progressValue/100);
        
        
        ctime=setInterval(
            function(){
                
                currentTime++;
                
                currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);
                
                state.audio.currentTime=currentMinute;
                state.audio.progressPercent=((playerBar.currentTime/playerBar.duration)*100).toFixed(1);
                
            },1000
        )

        playerBar.currentTime=currentTime;
        
        let currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);

        state.audio.currentTime=currentMinute;
    },
  1. 如代码所示,我在顶部导航增加了一个icon button,款式来自Muse-ui绑定了一个点击事宜backpage,点击后会回到上一个路由页面。这个须要合营之前的高亮底部导航icon,才完成返回上一路由的同时高亮相对应的icon。
  2. 还要注重的是,computed里有两个要领,第一个是猎取vuex内里的当前曲目信息;第二个则是猎取进度条的百分比信息,这个要领完成了数据的双向绑定,跟着背景设定的计时器,不断地更新,从而完成播放时进度条的变化。一样,这里的款式也是来自Muse-uiSlider
  3. 这里有一个须要注重的坑是,Muse-ui自带了许多的函数,第一次写的时刻没有注重,在进度条上绑定了一个mouseup事宜,效果无效,厥后才发明,实在已自带了change事宜,还可以完成挪动端的兼容。所以写代码的时刻一定要多看看官网文档。
  4. 关于store.js里的要领,play是播放/停息,详细会依据当前音频文件的paused(即是不是停息)来推断。总的道理是起首猎取音频的持续时刻,然后经由过程一个定时器,不断更新显现时刻,播放完成时,计时器住手。
  5. 计时器很症结,进度条和显现时刻的更新都须要它。然则计时器有个坑,假如把计时器声明放在play要领里,则没法在audioEnd要领里住手计时器,所以这里我们须要在最外层先声明一个ctime,然后再在play要领里把定时器赋值给ctime,如许我们就可以随时住手计时器了。
  6. audioEnd要领是播放住手时要做的事变,我们会把住手按钮切换成播放,把显现时刻修改掉,别忘了住手计时器。
  7. editProgress要领是点击或拖动进度条时做的事变,我们会转变当前音频的currentTime,即当前时刻,假如音频是停息状况,我们要让它继承播放。

4.search.vue

这也是一个比较中心的一个功用,毕竟引荐的歌单只需几个。看代码:

<template>
  <div class="search">

    <!-- navbar here -->
    <mu-appbar>
      <mu-icon-button icon="navigate_before" slot="left" v-on:click="backpage"/>
      <div class="logo searchLogo">
        iPlayer
      </div>
      <mu-text-field icon="search" class="appbar-search-field"  slot="right" hintText="想听什么歌?" v-model="searchKey"/>
      <mu-flat-button color="white" label="搜刮" slot="right" @click="getSearch(searchKey)"/>
    </mu-appbar>

    <!-- banner here-->

    
    <mu-list>       
      <template v-for="(item,index) in result.songs">
        <mu-list-item  :title="item.name" @click="getSong(item.id,item.name,item.artists[0].name,item.album.name,item.artists[0].id)">
          <mu-avatar slot="leftAvatar" backgroundColor="#fff" color="#bdbdbd">{{index+1}}</mu-avatar>
          <span slot="describe">
            <span style="color: rgba(0, 0, 0, .87)">{{item.artists[0].name}} -</span> {{item.album.name}}
          </span>
        </mu-list-item>
        <mu-divider/>
      </template>
    </mu-list>
    

    <div class="footer-rights">
      <h4>版权归Godown Huang一切,请<a href="https://github.com/WE2008311">联络我</a>。</h4>
    </div>


  </div>
</template>

<script>


export default {
  
  name: 'search',
  data(){
    return{
      searchKey:''
    }
  },
  computed:{
    result(){
      return this.$store.getters.result;
    }
  },
  
  components: {
    
  },
  
  methods:{
    backpage(){
      window.history.go(-1);
    },
    getSearch(value){
      this.$store.commit('getSearch',value);
    },
    getSong(id,name,singer,album,arid){
      
      
      this.$store.commit('getSong',{id,name,singer,album,arid});
      this.$store.commit('play');
    }
    
  }
}
</script>
  

<style lang="less">
  @media screen and (max-width: 525px){
    .searchLogo{
      display: none;
    }
    .appbar-search-field{
      width: 200px!important;
    }
  }
  
  .appbar-search-field {
    color: #FFF;
    margin-top: 10px;
    margin-bottom: 0;
    &.focus-state {
      color: #FFF;
    }
    .mu-icon {
      color: #FFF;
    }
    .mu-text-field-hint {
      color: fade(#FFF, 54%);
    }
    .mu-text-field-input {
      color: #FFF;
    }
    
    .mu-text-field-focus-line {
      background-color: #FFF;
    }
  }

  .footer-rights>h4{
    color: #e1e1e1;
    font-weight: 100;
    font-size:.056rem;
    height:90px;
    padding-top: 10px;
    text-align: center;
  }

</style>

store.js里增加:

getSearch(state,value){
        const url='http://localhost:3000/search?keywords='+value+'?limit=30';
        axios.get(url).then(res=>{
            state.result=res.data.result;
        })
        
    },
    getSong(state,{id,name,singer,album,arid}){
        const url="http://localhost:3000/music/url?id="+id;
        const imgUrl="http://localhost:3000/artist/album?id="+arid;
        const playerBar=document.getElementById("playerBar");
        

        axios.get(url).then(res=>{
            
            state.audio.location=res.data.data[0].url;
            state.audio.flag=res.data.data[0].flag;
            
            state.audio.songName=name;
            state.audio.singer=singer;
            state.audio.album=album;
        })
        axios.get(imgUrl).then(res=>{
            state.audio.picUrl=res.data.artist.picUrl;
        })
        
        let currentTime=playerBar.currentTime;
        let currentMinute=Math.floor(currentTime/60)+":"+(currentTime%60/100).toFixed(2).slice(-2);
        let duraTime=playerBar.duration;
        let duraMinute=Math.floor(duraTime/60)+":"+(duraTime%60/100).toFixed(2).slice(-2);

        state.audio.duration=duraMinute;
        state.audio.currentTime=currentMinute;
        state.audio.progressPercent=((playerBar.currentTime/playerBar.duration)*100).toFixed(1);
        
        
    }

注重,在有须要运用
axios的组件一定要
import,npm下载装置没必要多说了。

诠释一下这个组件的两个要领:

  1. getSearch是猎取搜刮效果,它被绑定再搜刮按钮上,初始页面是空缺,经由过程通报症结字,用axios从api猎取搜刮效果,再把效果显现在页面上。
  2. getSong绑定在每个搜刮的效果上,有两个步骤,第一是getSong,会把点击的歌曲设置为要播放的歌曲,并把相干信息通报给play.vue,让它显现在响应的处所;第二个步骤,会播放歌曲,也就是上面的play要领,详细没必要再说。
  3. 这里有一个坑,我们可以须要经由过程vuex通报参数,然则有时刻通报多个参数会涌现undefined的状况,这时刻我们要把参数们写成{参数一,参数二,参数三}的情势。

5.songList

这个组件主假如歌单详情页,基础的款式和搜刮页一样,就是猎取歌单的内容差别,搜刮页面的列表是依据症结词猎取的,歌单详情页的列表是依据歌单id猎取的,猎取的体式格局都是经由过程axios。

<template>
  <div class="songsList">

    <!-- navbar here -->
    <mu-appbar>
      <mu-icon-button icon="navigate_before" slot="left" v-on:click="backpage"/>
      <div class="logo">
        iPlayer
      </div>
    </mu-appbar>

    <!-- banner here-->

    <div class="listBgImg">
      <img :src="playlist.coverImgUrl" />
      <!-- 封面CD -->
      <mu-avatar  slot="left" :size="120" :src="playlist.coverImgUrl"/>
      
    </div>
    
    <mu-list>       
      <mu-sub-header>{{playlist.name}}</mu-sub-header>
      <template v-for="(item,index) in playlist.tracks">
        <mu-list-item  :title="item.name" @click="getSong(item.id,item.name,item.ar[0].name,item.al.name,item.ar[0].id)">
          <mu-avatar :src="item.al.picUrl" slot="leftAvatar"/>
          <span slot="describe">
            <span style="color: rgba(0, 0, 0, .87)">{{item.ar[0].name}} -</span> {{item.al.name}}
          </span>
        </mu-list-item>
        <mu-divider/>
      </template>
    </mu-list>
    
    <div class="footer-rights">
      <h4>版权归Godown Huang一切,请<a href="https://github.com/WE2008311">联络我</a>。</h4>
    </div>



  </div>
</template>

<script>


export default {
  
  name: 'songsList',
  data(){
    return{

    }
  },
  components: {
    
  },
  computed:{
      playlist(){
        return this.$store.getters.playlist;
      }
      
  },
  methods:{
    backpage(){
      window.history.go(-1);
    },
    getSong(id,name,singer,album,arid){
      this.$store.commit('getSong',{id,name,singer,album,arid});
      this.$store.commit('play');
      
    }
  }
}
</script>
  

<style lang="css">
    
  .listBgImg{
    height:200px;
    width:100%;
    background: #fff;
    overflow: hidden;
  }
  .listBgImg>img{
    width: 100%;
    filter:blur(30px);
    -webkit-filter: blur(30px); 
    -moz-filter: blur(30px);
    -ms-filter: blur(30px);
  }
  .listBgImg .mu-avatar{
    position: absolute;
    left: 50%;
    margin-left: -60px;
    top: 130px;
  }
  .mu-list .mu-sub-header{
    /* position: absolute; */
    top: 260px;
    font-size: 16px;
    /* text-align: center; */
  }
  
  

</style>

没什么须要诠释的,注重我们在getSong内里通报的多个参数。

6.playerBox.vue

<template>
  <div class="playerBox">
      
      <audio ref="myAudio" :src="audio.location" @ended="audioEnd" id="playerBar"></audio>

      <div class="controlBarBtn" v-show="judgement()">
        
          <mu-icon-button icon="skip_previous"/>
          <mu-icon-button class="addPlus" icon="play_arrow" @click="play"/>
          <mu-icon-button icon="skip_next"/>
      </div>
  </div>
  
</template>

<script>



export default {



  name: 'playerBox',
  data(){
    
    return{
      
    }
  },
  components: {
    
  },

  computed:{
    audio(){
      return this.$store.getters.audio;
    }
  },
  methods:{
    play(){
      this.$store.commit('play');
    },
    audioEnd(event){
      this.$store.commit('audioEnd',event);
    },
    judgement(){
      let path=this.$route.path;
      if(path=="/play"){
        return true;
      }else{
        return false;
      }
    }
  }
  
}
</script>
  

<style lang="less" >
  .controlBarBtn{
    position: absolute;
    z-index:12;
    width: 243px;
    margin-left: -121.5px;
    
    top: 83%;
    left: 50%;
  }

  .controlBarBtn i.mu-icon{
    font-size: 36px;
    color: #03a9f4;
    left: 50%;
    margin-left: -18px;
    position: absolute;
    top: 10%;
  }
  
  .controlBarBtn .addPlus{
    top: 16px;
    width: 80px!important;
    height: 80px!important;
    margin: 0 30px!important;
  }
  .controlBarBtn .addPlus i.mu-icon{
    font-size: 60px;
    margin-left: -30px;
    top: 10%;
  }
</style>

这个页面比较简朴,播放器audio标签,绑定了ended事宜,即播放完成后实行。
这里有一个坑,诠释一下:我把播放器按钮放在这里了,为何呢?之前我是放在play.vue里的,然则我发明一个题目,就是经由过程点击歌单的歌曲播放时,没法转变播放/停息按钮,为何呢?因为我转变按钮的要领是用innerHTML转变,我为何要用这类要领呢?因为Muse-ui的icon经由衬着,是以标签的值的情势涌现的。这就不能不猎取DOM了,然则假如把按钮写在play.vue里,在歌单页面时是猎取不到指定DOM的,因为当前页面基础没有这个DOM!只需把按钮写在在主组件里的playerBox.vue里,才猎取到指定DOM。

然则写在playBox.vue里又有一个题目,按钮会出如今每个页面里,然则我们只需它出如今播放页面就好了,所以我们在这里要给按钮绑定一个v-show,内里的内容就是推断是不是是在指定路由,假如是播放页面,就显现按钮,不是,就隐蔽按钮。

axios和网易云api

axios详细的设置我都在上面讲了,这里引见一款网易云的api和运用要领。

文档在此

引见一下运用要领,进入git把它下下来,在命令行实行:

$ node app.js

在浏览器输入地点:

localhost:3000

看到弹出的页面就申明服务器启动胜利了。然后我们可以在文档里查到详细要求的数据,比方banner啊,歌单啊,搜刮啊,都能要求。我们看到前面写的axios要求里的地点,都是详细要求的地点。

这里要注重的是,这个api默许的是没有开启跨域的,看app.js里有一段被隐蔽的代码就是跨域的相干设置,消除隐蔽即可。

bug和未完胜利用

现在还存在一个比较大的bug,就是在歌单点击播放时,点击第一次因为没办法猎取个去的url,没法播放,只需再点击一次才播放,这个bug临时还没有时刻处理,会尽快处理。

然后现在还没有完成的功用是播放列表,天然上一曲/下一曲按钮也没有用了,歌曲播放一遍也就住手了,这个功用不算难,抽空把它做出来。

参考资料

这个app参考了一些技术文章,给了我很大的启示,附上链接。
用vue百口桶写一个“以假乱真”的网易云音乐
DIY 一个本身的音乐播放器 2.0 来袭

结语

这个app前前后后,磨磨蹭蹭做了两个月,好歹总算是做完了。进修照样得找项目来做,虽然这个项目还很大略,然则照样get到许多知识点,关于我的进步照样蛮大的。

这类项目不算难,写过的人也多,所以百分之八十的题目都能百度出来,剩下的百分之二十,技术社区里提个问基础可以处理。项目照样得本身写一遍,写的过程当中才发明题目,也才想办法找到处理办法,事变总是会比你设想的要简朴一点。

项目不算大,但要一步步写下来总有可以有所脱漏,这里是我的GitHub,人人可以对照着看看有无脱漏。假如你喜欢我的项目,也愿望star或许fork一波~

    原文作者:WE2008311
    原文地址: https://segmentfault.com/a/1190000013061686
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞