闲来无事,利用VUE搭建了一个WEB音乐播放器。但由于前期没有构思好,导致项目进行不下去了。不过实现了最基本的功能。记录一下项目过程吧。
最终效果图如下:WEB音乐播放器

项目搭建

  1. 采用vue-cli3.0搭建脚手架。
  2. 采用babel+eslint配置。
    在这里插入图片描述
  3. 项目结构图(node_modules未显示)
    在这里插入图片描述

项目说明

  1. 播放器中定义了三个组件,App.vue(父组件),Content.vue,Controller.vue。
  2. 未采用npm安装的方式,而是采用直接引入js和css的方式。
  3. 引入了vue-resource进行网络请求。
  4. API来源于小伟博客。

代码

一、App组件
<template>
  <div id="app">
    <div class="search-box">
      <input class="form-control" type="text"  placeholder="搜索音乐,歌手,歌词,mv" v-model="keywords">
      <button class="btn btn-primary" @click="search">SOU一下</button>
    </div><br>
    <button class="btn btn-default" data-toggle="modal" data-target="#myModal">
            <span class="glyphicon glyphicon-camera"></span>定制皮肤
    </button>

    <!-- Modal -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">定制个性皮肤</h4>
          </div>
          <div class="modal-body">
            <input type="text" name="" id="" placeholder="请在此处粘贴您的背景图片地址" class="form-control" v-model="imglink">
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-danger" data-dismiss="modal">关闭</button>
            <button type="button" class="btn btn-primary" @click="changeImage">保存</button>
          </div>
        </div>
      </div>
    </div>

    <Content :musics='musics' @playStatus="getPlayStatus"></Content>
    <Control :playStatus="playStatus"></Control>
    
  </div>
</template>

<script>
import Content from './components/Content.vue'
import Control from './components/Control.vue'

export default {
    data() {
       return {
         keywords: '',
         musics: {},
         imglink: '',
         playStatus: {}
     }
    },
    components:{
      Content,
      Control
    },
    created: function(){
        this.$http.get('https://api.mlwei.com/music/api/?key=523077333&id=热门&type=so&cache=0&size=hq&nu=10')
        .then( (res)=>{
          this.musics = res.body.Body;
        })
    },
    methods:{
      search: function(){
        this.$http.get('https://api.mlwei.com/music/api/?key=523077333&id='+ this.keywords +'&type=so&cache=0&size=hq&nu=10')
        .then( (res)=>{
          this.musics = res.body.Body;
        })
      },
      changeImage: function(){
          $('#app').css({'background-image':'url('+this.imglink+')'});
      },
      getPlayStatus: function(playStatus){
          this.playStatus = playStatus;  
      }

      
    }
}

</script>

<style scoped>
#app{
  height: 100%;
  width: 100%;
}
.search-box{
  margin-left: 35%;
  margin-top: 4%;
}
.search-box input{
  display: inline;
  width: 30%;
}
button[class='btn btn-default']{
  float: right;
  margin-right: 160px;
  margin-top: 5px;
}
</style>
二、Content组件
<template>
    <div id="content">
        <ul class="nav nav-tabs bg-info" role="tablist">
            <li role="presentation"><a href="#">音乐</a></li>
            <li role="presentation"><a href="#">歌手</a></li>
            <li role="presentation"><a href="#">歌词</a></li>
            <li role="presentation"><a href="#">MV</a></li>
        </ul>
        <hr>
        <table>
            <thead>
                <td>操作</td>
                <td>歌曲名称</td>
                <td>歌手</td>
                <td>专辑</td>
            </thead>
            <tr v-for="(music,index) in musics" :key="music.mid">
                <td><a @click="play(index)"><span class="glyphicon glyphicon-play-circle"></span></a></td>
                <td>{{ music.title }}</td>
                <td>{{ music.author }}</td>
                <td>{{ music.album }}</td>
                <audio controls id="audio">
                    <source :src="music.url" type="audio/mpeg">
                </audio>
            </tr>
        </table>
    </div>
</template>

<script>
export default {
    props:['musics'],
    data(){
        return{
            playStatus : {'isPlay':false,'currentTime':0}
        }
    },
    methods:{
        play: function(index){  
                var audio = document.getElementsByTagName('audio')[index]; 
                if(audio.paused){
                    audio.load();
                    audio.play();
                    this.playStatus.isPlay = true;
                    this.playStatus.currentTime = audio.currentTime;
                    this.$emit('playStatus',this.playStatus);
                }else{
                    audio.pause();
                    this.playStatus.isPlay = false;
                    this.$emit('playStatus',this.playStatus);
                }   
            
            
       }
    }
    
}
</script>

<style scoped>
    ul{
        width: 80%;
        margin-left: 10%;
    }
    table{
        width: 80%;
        margin-left: 10%;
        line-height: 30px;
    }
    table>tr>td{
        border-bottom: 1px solid rgb(79.8%, 96%, 79.8%);
    }
    button{
        margin: 0;
        padding: 0;
        border: 1px solid transparent;  
        outline: none;  
        background-color:rgb(100%, 100%, 100%);
    }
    audio{
        display: none;
    }

</style>
三、Control组件
<template>
    <div id="control">
        <button class="btn btn-primary">
            <span class="glyphicon glyphicon-fast-backward"></span>
        </button>
        <button class="btn btn-primary" @click="play">
            <span :class="playStatus.isPlay ? 'glyphicon glyphicon-pause' : 'glyphicon glyphicon-play'"></span>
        </button>
        <button class="btn btn-primary">
            <span class="glyphicon glyphicon-fast-forward"></span>
        </button>
        <div class="progress" >
            <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
                <span class="sr-only">60% Complete</span>
            </div>
        </div>
        <div id="other">
            <button></button>
            <button>
                <span class="glyphicon glyphicon-repeat"></span>
            </button>
             <button>
                <span class="glyphicon glyphicon-film"></span>
            </button>
            <button></button>
        </div>

    </div>


</template>


<script>
export default {
    props: ['playStatus'],
    data(){
        return{
            playcss: 'glyphicon glyphicon-play', 
        }
    },
    methods:{
        play:function(){  
        }
    }
 
}
</script>

<style scoped>
    #control{
        width: 80%;
        padding-left: 10%;
        padding-top: 3%;
    }
    button{
        height: 40px;
        width: 40px;  
        border-radius: 50%;
        margin-right: 20px;
    }
    #progress{
        width: 60%;
        height: 3px;
    }
    div[class='progress']{
        height: 3px;
        width: 30%;
        position: absolute;
        left: 24%;
        top: 87%;
    }
    div[class='progress-bar']{
        width: 60%;
        height: 3px;
    }
    #other{
        position: absolute;
        left: 75%;
        top: 84%;
    }
</style>
四、main.js
import Vue from 'vue'
import App from './App.vue'
import VueResource from 'vue-resource'

Vue.config.productionTip = false
Vue.use(VueResource)

new Vue({
  render: h => h(App),
}).$mount('#app')

项目功能展示

  1. 定制皮肤
    采用bootstrap中的模态框对图片地址进行获取,并采用jQuery进行背景的渲染。
    在这里插入图片描述
    在这里插入图片描述
  2. 音乐搜索
    父组件调用API获取歌曲数据,将数据与Content组件进行绑定。Content利用props对数据进行获取并对页面进行渲染。
    在这里插入图片描述
  3. 音乐播放
    点击音乐所对应的播放键,生成歌曲状态信息(歌曲是否播放,歌曲播放进度),将歌曲信息先传递给父组件,再由父组件传递给Control组件,从而实现联动。
    问题就出在这里,由于vue的特性是子组件和子组件之间不能进行传值,因此,只能采取这种迂回的方法。
    歌曲处于播放状态
    歌曲处于暂停状态

项目总结

这个播放器的项目由于前期构思的问题,导致组件间传值变得很困难。因此,vue的项目在组件构思上一定要考虑组件间传值的问题。
项目中还遇到一个问题,在利用vue-resource进行请求的过程中,可能会出现无法请求的问题,这个时候一定要先对请求URL进行判断,其次,要注意请求的方式,小编在调用一个API时,调用成功,却始终无法取到返回值,就是在请求方式上出现了问题,最开始小编使用的是this.$http.get() 方法进行请求,最后采用this.$http.jsonp()成功请求并取到值。

Logo

前往低代码交流专区

更多推荐