场景
从今日推荐页面点击某首歌曲会将这首歌曲的songid通过路由传递到播放界面,
播放界面调用百度音乐接口实现数据的获取以及音乐的播放。
效果
实现
配置路由
首先在pages目录下新建musicplay.vue作为音乐播放的页面,
然后在router下的index.js中中配置路由。
routes: [
{
path:"/musicplay",
name:"MusicPlay",
component:MusicPlay
},
来到今日推荐页面,配置页面跳转
跳转到音乐播放组件并将当前音乐的songid通过路由参数传递过去。
<div class="scroller">
<router-link tag="div" :to="{name:'MusicPlay',params:{songid:item.song_id}}" class="card url" v-for="(item,index) in todayRecommend" :key="index">
<div class="album">
<img :src="item.pic_big" :alt="item.title">
<div class="name">{{ item.title }}</div>
</div>
</router-link>
</div>
同理将其他页面,要实现播放的页面组件也配置跳转到音乐播放组件,并将要播放的音乐组件的songid传递过去。
实现音乐播放界面
百度音乐API播放说明:
例:method=baidu.ting.song.play&songid=877578
例:method=baidu.ting.song.playAAC&songid=877578
参数:songid = 877578 //歌曲id
注:关于使用file_link不能播放的问题,是因为百度使用Http中的Referer头字段来防止盗链,在HTML文件中
加上 <meta name=”referrer” content=”never”>这一句让发送出去的Http包都不含Referer字段
来到musicplay.vue
CSS样式
<style scoped>
.header{
padding:15px;
}
.music-info{
flex: 1;
font-size: 20px;
}
.title{
display: flex;
text-align: center;
}
.left{
font-size: 30px;
}
.ca{
color: red;
}
.right{
font-size: 30px;
}
.song-info{
padding: 15px;
}
.song-info-img{
text-align: center;
}
.song-info-img img{
width: 50%;
border-radius: 5px;
box-shadow: 0 0 10px 0 rgba(50,50,50,.31);
}
.song-lrc{
margin-top: 10px;
min-height: 50px;
}
.iconbox{
display: flex;
margin-top: 30px;
}
.iconbox .box{
flex: 1;
}
.song{
width: 100%;
text-align: center;
}
.song audio{
width: 80%;
}
.active{
color: #222;
}
.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="music-info">
<p>{{ currentUrl.songinfo.title }}</p>
<p class="author">{{ currentUrl.songinfo.author }}</p>
</div>
<router-link to="/search"><i class="iconfont icon-sousuo right"></i></router-link>
</div>
</div>
<div class="song-info">
<div class="song-info-img">
<img :src="currentUrl.songinfo.pic_big">
<LRC :durationTime="durationTime" :currentTime="currentTime" :songid="this.$route.params.songid"/>
</div>
<div class="iconbox">
<i class="iconfont icon-shoucang2 left"></i>
<i class="box"></i>
<i class="iconfont icon-xiazai right"></i>
</div>
</div>
<div class="song">
<audio ref="player" :src="currentUrl.bitrate.show_link" controls autoplay></audio>
</div>
</div>
</template>
实现歌词滚动功能
在components目录下新建LRC.vue
<template lang="html">
<div class="lrcContainer">
<div class="lrc" ref="lrc">
{{ getAllKey }}
<p
class="lrc-p"
:class="{active:parseInt(currentTime) >= keyArr[index] && parseInt(currentTime) < keyArr[index+1]}"
v-for="(item,key,index) in lrcData"
:key="index">
{{ item }}{{ srcollLrc(key,index) }}
</p>
</div>
</div>
</template>
<script>
export default {
name:"lrc",
data(){
return{
lrc:{},
lrcData:{},
keyArr:[]
}
},
props:{
songid:{
type:[String,Number],
default:""
},
currentTime:{
type:[String,Number],
default:0
},
durationTime:{
type:[String,Number],
default:0
}
},
mounted(){
const LRCUrl = this.HOST+"/v1/restserver/ting?method=baidu.ting.song.lry&songid="+this.songid;
this.$axios.get(LRCUrl)
.then(res => {
this.lrc = res.data
// 数据格式处理
var lyrics = res.data.lrcContent.split("\n");
var lrcObj = {};
for(var i = 0 ;i<lyrics.length;i++){
var lyric = decodeURIComponent(lyrics[i]);
var timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g;
var timeRegExpArr = lyric.match(timeReg);
if(!timeRegExpArr)continue;
var clause = lyric.replace(timeReg,'');
for(var k = 0,h = timeRegExpArr.length;k < h;k++) {
var t = timeRegExpArr[k];
var min = Number(String(t.match(/\[\d*/i)).slice(1)),
sec = Number(String(t.match(/\:\d*/i)).slice(1));
var time = min * 60 + sec;
lrcObj[time] = clause;
}
}
this.lrcData = lrcObj;
})
.catch(error => {
console.log(error);
})
},
computed:{
getAllKey(){
for(var i in this.lrcData){
this.keyArr.push(i);
}
}
},
methods:{
srcollLrc(key,index){
const lrcDiv = this.$refs.lrc
if(key < this.currentTime && key > this.currentTime - (this.keyArr[index+1] - this.keyArr[index])){
lrcDiv.style.top = -((index-2)*30)+"px"
}
}
}
}
</script>
<style scoped>
.lrcContainer{
width: 100%;
height: 150px;
overflow: hidden;
position: relative;
}
.lrc{
width: 100%;
position: absolute;
top: 0;
}
.active{
color: red !important;
}
.lrc-p{
height: 30px;
line-height: 30px;
}
.up30{
margin-top: -30px;
}
</style>
在musicplay.vue显示歌词滚动
<div class="song-info-img">
<img :src="currentUrl.songinfo.pic_big">
<LRC :durationTime="durationTime" :currentTime="currentTime" :songid="this.$route.params.songid"/>
</div>
在musicplay.vue异步操作
// 异步操作
const LRC = Vue.component("lrc",(resolve)=>require(["../components/LRC"],resolve))
添加监听
methods:{
addEventListeners(){
this.$refs.player.addEventListener('timeupdate', this._currentTime),
this.$refs.player.addEventListener('canplay', this._durationTime)
},
removeEventListeners: function () {
this.$refs.player.removeEventListener('timeupdate', this._currentTime)
this.$refs.player.removeEventListener('canplay', this._durationTime)
},
_currentTime(){
this.currentTime = this.$refs.player.currentTime
// currentTime是audio标签提供的获取当前播放时间的方法
},
_durationTime(){
this.durationTime = this.$refs.player.duration
// duration是audio标签提供的获得歌曲播放整体时间的方法
}
}
实现下载功能
百度音乐API下载说明:
例:method=baidu.ting.song.downWeb&songid=877578&bit=24&_t=1393123213
参数: songid = 877578//歌曲id
bit = 24, 64, 128, 192, 256, 320 ,flac//码率
_t = 1430215999,, //时间戳
我们在请求百度音乐的API后输出返回的数据可以看到
歌曲的链接为:
返回数据下的bitrate下的show_link
所以我们几将audio的src属性设为
<div class="song">
<audio ref="player" :src="currentUrl.bitrate.show_link" controls autoplay></audio>
</div>
所以我们点击播放组件的右边的三个点,选择下载,就可以实现下载了。
完整musicplay.vue代码
<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-info">
<p>{{ currentUrl.songinfo.title }}</p>
<p class="author">{{ currentUrl.songinfo.author }}</p>
</div>
<router-link to="/search"><i class="iconfont icon-sousuo right"></i></router-link>
</div>
</div>
<div class="song-info">
<div class="song-info-img">
<img :src="currentUrl.songinfo.pic_big">
<LRC :durationTime="durationTime" :currentTime="currentTime" :songid="this.$route.params.songid"/>
</div>
<div class="iconbox">
<i class="iconfont icon-shoucang2 left"></i>
<i class="box"></i>
<i class="iconfont icon-xiazai right"></i>
</div>
</div>
<div class="song">
<audio ref="player" :src="currentUrl.bitrate.show_link" controls autoplay></audio>
</div>
</div>
</template>
<script>
import Vue from "vue"
import "../assets/font/iconfont.css"
// import LRC from "../components/LRC"
// 异步操作
const LRC = Vue.component("lrc",(resolve)=>require(["../components/LRC"],resolve))
export default {
name:"musicplay",
data(){
return{
currentUrl:{
songinfo:{
title:"",
author:""
},
bitrate:{
show_link:""
}
},
currentTime:0,
durationTime:0
}
},
components:{
LRC
},
mounted(){
const playUrl = this.HOST+"/v1/restserver/ting?method=baidu.ting.song.play&songid=" + this.$route.params.songid;
this.$axios.get(playUrl)
.then(res => {
this.currentUrl = res.data;
})
.catch(error => {
console.log(error);
})
this.addEventListeners();
},
beforeDestroyed(){
this.removeEventListeners();
},
methods:{
addEventListeners(){
this.$refs.player.addEventListener('timeupdate', this._currentTime),
this.$refs.player.addEventListener('canplay', this._durationTime)
},
removeEventListeners: function () {
this.$refs.player.removeEventListener('timeupdate', this._currentTime)
this.$refs.player.removeEventListener('canplay', this._durationTime)
},
_currentTime(){
this.currentTime = this.$refs.player.currentTime
// currentTime是audio标签提供的获取当前播放时间的方法
},
_durationTime(){
this.durationTime = this.$refs.player.duration
// duration是audio标签提供的获得歌曲播放整体时间的方法
}
}
}
</script>
<style scoped>
.header{
padding:15px;
}
.music-info{
flex: 1;
font-size: 20px;
}
.title{
display: flex;
text-align: center;
}
.left{
font-size: 30px;
}
.ca{
color: red;
}
.right{
font-size: 30px;
}
.song-info{
padding: 15px;
}
.song-info-img{
text-align: center;
}
.song-info-img img{
width: 50%;
border-radius: 5px;
box-shadow: 0 0 10px 0 rgba(50,50,50,.31);
}
.song-lrc{
margin-top: 10px;
min-height: 50px;
}
.iconbox{
display: flex;
margin-top: 30px;
}
.iconbox .box{
flex: 1;
}
.song{
width: 100%;
text-align: center;
}
.song audio{
width: 80%;
}
.active{
color: #222;
}
.author{
font-size: 12px;
color: #999;
}
</style>
解决Referrer Policy: no-referrer-when-downgrade
场景
原因
百度使用Http中的Referer头字段来防止盗链,在HTML文件中加上 <meta name=”referrer” content=”never”>这一句让发送出去的Http包都不含Referer字段就行了
解决
找到index.html
加入
<meta name="referrer" content="never">
注意双引号是英文状态