Vue音乐播放器
目录
Vue音乐播放器
前言
本项目是基于vue3实现的一个音乐播放器,该项目是从网易云音乐接口获取相关音乐数据,再通过播放音乐的相关插件工具来实现给用户展示与播放功能。
主要功能展示
- 首页功能展示
- 实现音乐播放功能
- 实现音乐视频播放功能
- 实现搜索功能
主要功能代码实现
首页代码
<template lang="html">
<div class="css">
<ul>
<li>
<router-link to="/home">
首页
</router-link>
</li>
<li>
<router-link to="/search">
搜索
</router-link>
</li>
</ul>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.css {
background-color: #f8f6f6;
}
.css ul{
display: flex;
height: 50px;
line-height: 50px;
background: #efafaf;
}
.css ul li {
flex: 1;
text-align: center;
}
.css ul li a{
font-size: 16px;
color: #0e0b0b;
}
</style>
音乐播放功能
<template lang="html">
<div class="play">
<div class="header">
<div class="title">
<router-link to="/">
<i class="iconfont icon-shouye left"></i>
</router-link>
<div class="music">
<p>{{this.name}}</p>
<span
class="author"
v-for="(item,index) in this.author"
:key="index"
style="margin-right:2px"
>{{item.name}}</span>
</div>
<router-link to="/search">
<i class="iconfont icon-sousuo right"></i>
</router-link>
</div>
</div>
<div class="songs">
<div class="songs-img">
<img :src="this.songPic" :alt="this.name" />
</div>
</div>
<div class="songPlay">
<audio ref="player" :src="this.songUrl" controls autoplay></audio>
</div>
</div>
</template>
<script>
import "../assets/font/iconfont.css"//音乐播放器样式引入
export default {
name:"MusicPlay",
props: {
songid: {//接收传递的参数
type: [String, Number],
default: ""
}
},
data() {
return {//保存请求得到的参数
songUrl:" ",
songPic:"",
name:"",
author:[],
};
},
mounted(){//请求参数
if(this.$route.params.songid){
// 获取歌曲详情
let songDetsil = this.HOST + `/song/detail?ids=${this.$route.params.songid}`;
// 获取歌曲url地址
let songUrls = this.HOST + `/song/url?id=${this.$route.params.songid}`;
// 发起请求
this.$axios.get(songDetsil).then(res => {
this.songPic=res.data.songs[0].al.picUrl
this.name=res.data.songs[0].name
this.author=res.data.songs[0].ar
this.$axios.get(songUrls).then(res => {
this.songUrl= res.data.data[0].url;
})
.catch(err => console.log('获取歌曲音频报错', err.response.data.message));
})
.catch(err => {
console.log('获取歌曲信息报错', err.response.data.message);
});
}
},
}
</script>
<style scoped>
.play{
background-color: #f4cccc;
}
.header{
padding:15px;
background-color: #efafaf;
}
.music{
flex: 1;
font-size: 20px;
}
.title{
display: flex;
text-align: center;
}
.left{
font-size: 30px;
}
.right{
font-size: 30px;
}
.songs{
padding: 15px;
margin-top: 30px;
}
.songs-img{
width:345px;
height:280px;
}
.songPlay{
width: 100%;
display: flex;
margin-top: 40px;
}
.songPlay audio{
width: 100%;
}
.author{
font-size: 12px;
color: #999;
}
</style>
视频播放功能
<template lang="html">
<div class="play">
<div class="header">
<div class="title">
<router-link to="/">
<i class="iconfont icon-shouye left"></i>
</router-link>
<div class="movie">
<p>{{this.name}}</p>
</div>
<router-link to="/search">
<i class="iconfont icon-sousuo right"></i>
</router-link>
<br>
</div>
</div>
<Video
:videoUrl="fileUrl"
:coverUrl="coverUrl"
></Video>
</div>
</template>
<script>
import "../assets/font/iconfont.css"//样式
import Video from "../components/Video.vue"
export default {
props: {
mvid: {//接收参数
type: [String, Number],
default: ""
}
},
components:{
Video
},
data() {
return {
// 视频数据
name:"",
fileUrl: "",
coverUrl: "",
};
},
mounted(){
if(this.$route.params.mvid){
// 获取歌名、歌手、时长、id
let mvCover = this.HOST + `/mv/detail?mvid=${this.$route.params.mvid}`;
// 获取歌曲音频
let mvUrl = this.HOST + `/mv/url?id=${this.$route.params.mvid}`;
// 发起请求
this.$axios.get(mvCover).then(res => {
this.coverUrl=res.data.data.cover
this.name=res.data.data.name
console.log(this.coverUrl)
this.$axios.get(mvUrl).then(res => {
console.log(res.data.data)
this.fileUrl=res.data.data.url
})
.catch(err => console.log('获取视频详情报错', err.response.data.message));
})
.catch(err => {
console.log('获取视频url信息报错', err.response.data.message);
});
}
}
}
</script>
<style scoped>
.play{
background-color: #f4cccc;
}
.header{
padding:15px;
background-color: #efafaf;
}
.movie{
flex: 1;
font-size: 20px;
}
.title{
display: flex;
text-align: center;
}
.left{
font-size: 30px;
}
.right{
font-size: 30px;
}
.songs{
padding: 15px;
margin-top: 40px;
}
</style>
搜索功能
<template lang="html">
<div class="search">
<div class="title">
<input type="text" name="" placeholder="请输入搜索内容" v-model="Content">
<button type="button" @click="search" name="button">搜索</button>
</div>
<ul class="list ">
<router-link :key="index" tag="li"
:to="{name:'MusicPlay',
params:{songid:item.id}}"
class="song" v-for="(item,index) in list">
<div class="left">
<div class="name ">
<div>
<span>{{ item.name }}</span>
</div>
<span >{{ item.artists[0].name}}</span>
</div>
</div>
</router-link>
</ul>
</div>
</template>
<script>
export default {
name:"Search",
data(){
return{//保存获得的参数
Content:"",
list:[]
}
},
methods:{
search(){//通过拼接地址方法,请求网络数据
const URL = this.HOST + `/search?keywords=${this.Content}`;
this.$axios.get(URL)
.then(res => {
if(res.data.error_code == 22001){
alert('搜索数据不存在');
return ;
}
this.list = res.data.result.songs
})
.catch(error => {
console.log(error);
})
}
}
}
</script>
<style scoped>
.search{
background-color: #f4cccc;
}
.title{
padding: 20px;
overflow: hidden;
clear: both;
}
button{
background-color: #efafaf;
}
input{
width: 80%;
height: 30px;
line-height: 30px;
background: #f4cccc;
border: 1px solid #f4cccc;
padding-left: 10px;
float: left;
display: inline-block;
}
button{
float: left;
width: 15%;
height: 30px;
}
.list {
word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
word-break: break-all;
border-bottom: 1px solid #f4cccc;
border-top: 1px solid #f4cccc;
}
.song {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
min-height: 55px;
text-align: left;
}
li{
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-box-sizing: border-box;
box-sizing: border-box;
min-height: 50px;
border-bottom: 1px solid #f4cccc;
padding-left: 10px;
}
.name {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.name>span {
font-weight: 400;
display: block;
font-size: 12px;
color: #f69a9a;
}
</style>
主要调用的组件
- 音乐播放组件
<template lang="html">
<div class="search">
<div class="title">
<input type="text" name="" placeholder="请输入搜索内容" v-model="Content">
<button type="button" @click="search" name="button">搜索</button>
</div>
<ul class="list ">
<router-link :key="index" tag="li"
:to="{name:'MusicPlay',
params:{songid:item.id}}"
class="song" v-for="(item,index) in list">
<div class="left">
<div class="name ">
<div>
<span>{{ item.name }}</span>
</div>
<span >{{ item.artists[0].name}}</span>
</div>
</div>
</router-link>
</ul>
</div>
</template>
<script>
export default {
name:"Search",
data(){
return{//保存获得的参数
Content:"",
list:[]
}
},
methods:{
search(){//通过拼接地址方法,请求网络数据
const URL = this.HOST + `/search?keywords=${this.Content}`;
this.$axios.get(URL)
.then(res => {
if(res.data.error_code == 22001){
alert('搜索数据不存在');
return ;
}
this.list = res.data.result.songs
})
.catch(error => {
console.log(error);
})
}
}
}
</script>
<style scoped>
.search{
background-color: #f4cccc;
}
.title{
padding: 20px;
overflow: hidden;
clear: both;
}
button{
background-color: #efafaf;
}
input{
width: 80%;
height: 30px;
line-height: 30px;
background: #f4cccc;
border: 1px solid #f4cccc;
padding-left: 10px;
float: left;
display: inline-block;
}
button{
float: left;
width: 15%;
height: 30px;
}
.list {
word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
word-break: break-all;
border-bottom: 1px solid #f4cccc;
border-top: 1px solid #f4cccc;
}
.song {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
min-height: 55px;
text-align: left;
}
li{
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-box-sizing: border-box;
box-sizing: border-box;
min-height: 50px;
border-bottom: 1px solid #f4cccc;
padding-left: 10px;
}
.name {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.name>span {
font-weight: 400;
display: block;
font-size: 12px;
color: #f69a9a;
}
</style>
- 视频播放组件
<template>
<div class="play">
<div class="player-box">
<video-player
class="video-player vjs-custom-skin"
ref="VideoPlay"
:playsinline="true"
:options="playerOptions"
></video-player>
</div>
</div>
</template>
<script>
export default {
props: {
videoUrl: {
type: String,
required: true,
},
coverUrl: {
type: String,
required: true,
},
},
data() {
return {
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
autoplay: false, //如果true,浏览器准备好时开始回放。
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 导致视频一结束就重新开始。
preload: "auto", // auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: "zh-CN",
aspectRatio: "16:9", // 将播放器置于流畅模式
fluid: true, // 实现按比例缩放以适应容器。
sources: [
{
type: "", //种类
src: this.videoUrl, //url地址
},
],
poster: this.coverUrl, //你的封面地址
controlBar: {
timeDivider: true,
durationDisplay: true,
remainingTimeDisplay: false,
fullscreenToggle: true, //全屏按钮
},
},
};
},
watch: {
videoUrl(val) {
this.playerOptions.sources[0].src = val;
},
coverUrl(val) {
this.playerOptions.poster = val;
},
},
};
</script>
<style scoped>
.play{
background-color: #f4cccc;
/* overflow-y:scroll ; ::-webkit-scrollbar*/
}
.header{
padding:15px;
background-color: #efafaf;
}
.movie{
flex: 1;
font-size: 20px;
}
.title{
display: flex;
text-align: center;
}
.left{
font-size: 30px;
}
.right{
font-size: 30px;
}
.songs{
padding: 15px;
margin-top: 40px;
}
.song-img{
/* text-align: center; */
width:345px;
height:280px;
}
.songPlay{
width: 100%;
display: flex;
/* text-align: center; */
margin-top: 40px;
}
.songPlay audio{
width: 100%;
}
.active{
color: #222;
}
.author{
font-size: 12px;
color: #999;
}
</style>
项目不足
1.各类访问数据是从线上获取,缺少对数据层的开发与管理功能。
2.未实现用户的注册及登录页面,播放器的安全性较低。
3.用户可操作的功能较少。
个人小结
由于目前本项目的功能尚未达到理想版本,我想下次更新一下,再来进一步补充该项目的介绍并附上源码。