📖手撸Vue 实现音乐播放功能

前言

因为之前一直想弄一个音乐播放的站点,但不知道用什么框架去写比较好,恰好看见一个可以用的网易云音乐API打算用来测试下

所以样式我就没怎么太注意去写了,功能也是简单实用的几个,可以用来挂着听歌(虽然没有软件好用)

代码量比较多,嫌麻烦的可以直接复制源码,源码我也写了很多译释,直接复制下来放到自己页面应该可以运行

框架:Vue-cli,jQuery,bootstrap,
音乐播放站点 》》

手撸Vue 实现音乐播放功能插图

源码

废话不多说,直接上源码

<template>
	<div id="music">
		<div class="b_img"><img src="../../assets/image/musicimg.jpg"></div>
		<div id="back_img"><div style="height:37px;background-color:#fff;z-index: 1;position: relative;"></div><img v-bind:src="muimg"></div>
		<div id="music_bo">
			<div class="title">
				<p class="title_h1">歌名:{{gename}}</p>
				<p class="title_info">歌手:<b v-for="name in usname">{{name}}&nbsp;&nbsp;&nbsp;</b></p>
			</div>
			<div class="in_left"><button @click="musicshang()" class="no_button"><i class="glyphicon glyphicon-step-backward" title="上一首"></i></button></div>
			<div class="in_img"><img v-bind:src="muimg" class="max_img">
			<button class="zan_an" @click="bo()"><i class="glyphicon glyphicon-play" title="暂停"></i></button></div>
			<div class="in_right">
				<button @click="musicxia()" class="no_button"><i class="glyphicon glyphicon-step-forward" title="下一首"></i></button>
				<button class="no_button list_ge" @click='gelist()'><i class="glyphicon glyphicon-th-large" title="歌单列表"></i></button>
			</div>
			<audio controls v-bind:src="bofangmu" id="xqt"></audio>
		</div>
		<button @click="shou()" class="ce_bun"><i class="glyphicon glyphicon-chevron-left"></i></button>
		<div id="ge_dan">
			<div class="list-group">
				<a href="javascript:;" class="list-group-item active">
					<h4 class="list-group-item-heading">歌单</h4>
				</a>
				<ul class="listgun_ul">
					<a href="javascript:;" class="list-group-item" v-for="list in gedan" @click='listfun(list.id)'>
						<h4 class="list-group-item-heading">{{list.name}}</h4>
					</a>
				</ul>
			</div>
		</div>
	</div>
</template>
<script>
const axios = require('axios');
	export default{
		name:"music",
		data(){
			return {
				music:[1364400123,480426313,1309896289,1344897943,1360740361,1426649237,1404906595,480353,2059056,29482234,1400256289,1406642934,1386259535,1409329655,1335580481,527957820,468176711,574566207,1316460171,536099160,534542079,1313354324,27890306,1328146041,31445554,552594869,471565190,480580003,425828896,29004400,514761281,536502758,1330348068,25706282,32083133,1460474276,4879345,524543708,427606780,1410840088,760037,492145159,461544312,507585220,411314681,465920383,21253966,28248872,1491585,1321385655,863046037,515601126,30212890,422132115,533465371,440208476,410802679,1313107065,438981337,465675773,5162502,17753288,29769734,21038748,409931224,534542015,18161816,2918954,463352636,26565006,19081573,28830412,26429346,466122460,21253958,444269135,440101136,418602088,19542383,455653437,27946894,468882985,19711382,29009655,466794339,32574252,3570196,1345018,461347998,36990266,28681438],
				bofangmu:'',//歌曲url
				muimg:'',//歌曲封面图片
				gename:'',//歌曲名
				usname:[],//歌手
				gedan:[],//歌单
				arynum:0,//获取上方歌曲ID
				shou_s:true//点击展开与隐藏
			};
		},
		mounted(){
			var that=this;
			this.axiosmu(this.music[this.arynum]);
			let player = document.getElementById('xqt');
			player.ontimeupdate = function () {
				if(player.currentTime == player.duration){//判断当前歌曲是否播放完
					that.musicxia();//执行下一首
				}
			}
		},
		methods:{
			axiosmu(numb){//获取歌曲信息
				var that =this;//解决this:null问题
				axios.all([this.getUserAccount(numb), this.getUserPermissions(numb)])//并发执行函数
			  	.then(axios.spread(function (acct, perms) {
				  	that.bofangmu = acct.data.data[0].url;//获取歌的链接
				  	that.muimg =perms.data.songs[0].al.picUrl;//获取图片链接
				  	that.gename =perms.data.songs[0].al.name;//获取歌名

				  	for(let i=0;i<perms.data.songs[0].ar.length;i++){//循环获取歌手
				  		that.usname[i]=perms.data.songs[0].ar[i].name;
				  	}
			  	}));
			},
			getUserAccount(e) {return axios.get('https://api.imjad.cn/cloudmusic/?id='+e);},//获取音乐链接
			getUserPermissions(e) {return axios.get('https://api.imjad.cn/cloudmusic/?type=detail&id='+e);},//获取图像
			musicxia(){//下一首
				let ap = this.music[this.arynum+=1];
				if(this.arynum>=this.music.length){
					this.arynum=0;
					this.axiosmu(ap);//发送下一首ID
				}else{
				let that=this;
				this.axiosmu(ap);
				setTimeout(function () {//利用定时器功能下一首时,自动播放
			  		that.xia_bo();
				},1000)
			}
			},
			musicshang(){//上一首
				let that=this;
				let ap = this.music[this.arynum-=1];
				if (this.arynum<0) {
					this.arynum=this.music.length;
					this.axiosmu(ap);//发送上一首ID
				}else{
				this.axiosmu(ap);
				setTimeout(function () {//利用定时器功能下一首时,自动播放
			  		that.xia_bo();
				},1000)
				}
			},
			bo(){//点击播放按钮
				let player = document.getElementById('xqt');
				if(player.paused){
					player.play();
					$(".glyphicon-play").addClass("glyphicon-pause");
					$(".in_img").addClass("dong");
					$(".zan_an").removeClass("zan_an_au");
				}else{
					player.pause();
					$(".glyphicon-play").removeClass("glyphicon-pause");
					$(".in_img").removeClass("dong");
					$(".zan_an").addClass("zan_an_au");
				}
			},
			xia_bo(){//点击下一首与上一首开始播放
				let player = document.getElementById('xqt');
					player.play();
					$(".glyphicon-play").addClass("glyphicon-pause");
					$(".in_img").addClass("dong");
					$(".zan_an").removeClass("zan_an_au");
			},
			shou(){//展开与隐藏歌曲控件
				$('#music_bo').animate({width:'toggle'},350);
				$('#back_img').animate({width:'toggle'},350);
				if(this.shou_s){
					$('.ce_bun').animate({left:'0'},350);
					$('.ce_bun i').css({"transform":"rotate(180deg)","color":"#bd3a3a"});
					this.shou_s =false;
				}else{
					$('.ce_bun').animate({left:'310px'},350);
					$('.ce_bun i').css({"transform":"rotate(0deg)","color":"#fff"});
					this.shou_s =true;
				}
			},
			gelist(e){//歌单列表
				var that =this;//解决this:null问题
				if (this.gedan<=1) {
					for(let i=0;i<this.music.length;i++){
						axios
					      .get('https://api.imjad.cn/cloudmusic/?type=detail&id='+this.music[i])
					      .then(response => (//在数组的底部增加新元素
					      	that.gedan.push({id:response.data.songs[0].id,name:response.data.songs[0].al.name})
					      	))
					}
					$("#ge_dan").slideToggle("slow");
				}else{
					$("#ge_dan").slideToggle("slow");
				}
				$(".list_ge").toggleClass("red");
			},
			listfun(id){//点击列表的播放时
				let that=this;
				this.axiosmu(id);
			}
      }
	}
</script>
<style scoped>
.red{color:#bd3a3a!important;border:2px solid #bd3a3a!important;}
body{
	background-color: #E5F3FE;
}
.max_img{
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 88px;
border: 2px solid #fff;
}
#back_img{
	position: absolute;
top: 400px;
z-index: 1;
width: 310px;
filter: blur(20px);
height: 200px;
border-radius: 20px;
overflow: hidden;
}
#back_img img{width: 108%;height: 100%;margin-top: -13%;}
#music{margin-top: -20px;}
.b_img{height: calc(100vh);width:100%;overflow: hidden;}
.b_img img{width:100%}

#music_bo{
padding: 10px;
position: absolute;
top: 400px;
z-index: 2;
width: 310px;
height: 181px;
overflow: hidden;

border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
}
.title{background-color:#fff;}
.title_h1,.title_info{color:#000;
width:50%;
float:left;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;}
#xqt{
	width: 158%;
height: 26px;
margin-left: -17%;
border-radius: 15px;
overflow: hidden;
background-color: #fff;
margin-top: 5%;
}

.in_left{width: 32%;float: left;}
.in_img{width: 35%;float: left;overflow: hidden;max-height: 100px;}
.in_right{width: 32%;float: left;}
.dong{animation:myfirst 5s infinite linear;}

@keyframes myfirst
{
	0%   {transform:rotate(0deg);}
	10%  {transform:rotate(36deg);}
	20% {transform:rotate(72deg);}
	30% {transform:rotate(108deg);}
	40% {transform:rotate(144deg);}
	50% {transform:rotate(180deg);}
	60% {transform:rotate(216deg);}
	70% {transform:rotate(252deg);}
	80% {transform:rotate(288deg);}
	90% {transform:rotate(324deg);}
	100% {transform:rotate(360deg);}
}
.zan_an_au{color:#bd3a3a!important;border:2px solid #bd3a3a!important;opacity: 1!important;}
.in_img:hover >.zan_an{opacity: 1;transition: 1s;}
.zan_an{
	transition: 1s;
	opacity: 0;
	background: none;
    border: 2px solid #fff;
    position: relative;
    top: -76px;
    width: 50px;
    height: 50px;
    border-radius: 33px;
    color:#fff;
}
.no_button{
	background: none;
border: 2px solid #fff;
font-size: 16px;
border-radius: 15px;
color: #fff;
margin:10%;
width: 28%;
height: 28px;
}
.zan_an i{
	font-size:22px;
}
.ce_bun{
position: absolute;
top: 421px;
left: 310px;
z-index: 3;
height: 50px;
width: 29px;
font-size: 19px;
background: #5347478a;
border: none;
color: #fff;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
#ge_dan{
display:none;
position: absolute;
top: 54px;
right: 0px;
width: 20%;
}
.listgun_ul{
	overflow: auto;
height: 600px;
width:100%;
padding: 0;
}
.listgun_ul a h4{
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.list_ge{
	text-align: right;
}
</style>

JS 分块解释

data(){
	return {
		music:[1364400123,480426313,1309896289,1344897943,1360740361,1426649237,1404906595,480353,2059056,29482234,1400256289,1406642934,1386259535,1409329655,1335580481,527957820,468176711,574566207,1316460171,536099160,534542079,1313354324,27890306,1328146041,31445554,552594869,471565190,480580003,425828896,29004400,514761281,536502758,1330348068,25706282,32083133,1460474276,4879345,524543708,427606780,1410840088,760037,492145159,461544312,507585220,411314681,465920383,21253966,28248872,1491585,1321385655,863046037,515601126,30212890,422132115,533465371,440208476,410802679,1313107065,438981337,465675773,5162502,17753288,29769734,21038748,409931224,534542015,18161816,2918954,463352636,26565006,19081573,28830412,26429346,466122460,21253958,444269135,440101136,418602088,19542383,455653437,27946894,468882985,19711382,29009655,466794339,32574252,3570196,1345018,461347998,36990266,28681438],
		bofangmu:'',//歌曲url
		muimg:'',//歌曲封面图片
		gename:'',//歌曲名
		usname:[],//歌手
		gedan:[],//歌单
		arynum:0,//获取上方歌曲ID
		shou_s:true//点击展开与隐藏
	};
},

DATA

music 存放歌曲ID

这里存放的都是网易云歌曲的ID,鼠标移到到网页版的网易云可以看见ID

mounted(){
	var that=this;
	this.axiosmu(this.music[this.arynum]);
	let player = document.getElementById('xqt');
	player.ontimeupdate = function () {
		if(player.currentTime == player.duration){//判断当前歌曲是否播放完
			that.musicxia();//执行下一首
		}
	}
},

mounted 生命周期函数

主要作用还是获取需要播放第一首歌的信息

player.ontimeupdate 用来判断当前页面歌曲死否播放完,自动播放下一首

axiosmu(numb){//获取歌曲信息
	var that =this;//解决this:null问题
	axios.all([this.getUserAccount(numb), this.getUserPermissions(numb)])//并发执行函数
	.then(axios.spread(function (acct, perms) {
		that.bofangmu = acct.data.data[0].url;//获取歌的链接
		that.muimg =perms.data.songs[0].al.picUrl;//获取图片链接
		that.gename =perms.data.songs[0].al.name;//获取歌名

		for(let i=0;i<perms.data.songs[0].ar.length;i++){//循环获取歌手
			that.usname[i]=perms.data.songs[0].ar[i].name;
			}
	}));
}

由于歌曲信息不是放在同一个API中所以需要同时获取多个API接口,通过 axios.all的 并发功能获取

演唱歌手也不是只有一位,所以循环获得

getUserAccount(e) {return axios.get('https://api.imjad.cn/cloudmusic/?id='+e);},//获取音乐链接
getUserPermissions(e) {return axios.get('https://api.imjad.cn/cloudmusic/?type=detail&id='+e);},//获取图像

实际获取API信息的是这俩函数

	musicxia(){//下一首
		let ap = this.music[this.arynum+=1];
		if(this.arynum>=this.music.length){
			this.arynum=0;
			this.axiosmu(ap);//发送下一首ID
		}else{
			let that=this;
			this.axiosmu(ap);
			setTimeout(function () {//利用定时器功能下一首时,自动播放
			  that.xia_bo();
			,1000)
			}
		},
	musicshang(){//上一首
		let that=this;
		let ap = this.music[this.arynum-=1];
		if (this.arynum<0) {
			this.arynum=this.music.length;
			this.axiosmu(ap);//发送上一首ID
		}else{
		this.axiosmu(ap);
		setTimeout(function () {//利用定时器功能下一首时,自动播放
			  that.xia_bo();
		},1000)
		}
	},

上一首,获取歌曲ID列表的总长度来判定上一首歌的ID,下一首的功能也是如此

	bo(){//点击播放按钮
		let player = document.getElementById('xqt');
		if(player.paused){
			player.play();
			$(".glyphicon-play").addClass("glyphicon-pause");
			$(".in_img").addClass("dong");
			$(".zan_an").removeClass("zan_an_au");
		}else{
			player.pause();
			$(".glyphicon-play").removeClass("glyphicon-pause");
			$(".in_img").removeClass("dong");
			$(".zan_an").addClass("zan_an_au");
		}
	},
	xia_bo(){//点击下一首与上一首开始播放
		let player = document.getElementById('xqt');
			player.play();
			$(".glyphicon-play").addClass("glyphicon-pause");
			$(".in_img").addClass("dong");
			$(".zan_an").removeClass("zan_an_au");
	},

bo()歌曲图片上面那个播放暂停按钮

xia_bo()点击下一首与上一首时判定的音乐播放

	shou(){//展开与隐藏歌曲控件
		$('#music_bo').animate({width:'toggle'},350);
		$('#back_img').animate({width:'toggle'},350);
		if(this.shou_s){
			$('.ce_bun').animate({left:'0'},350);
			$('.ce_bun i').css({"transform":"rotate(180deg)","color":"#bd3a3a"});
			this.shou_s =false;
		}else{
			$('.ce_bun').animate({left:'310px'},350);
			$('.ce_bun i').css({"transform":"rotate(0deg)","color":"#fff"});
			this.shou_s =true;
		}
	},
	gelist(e){//歌单列表
		var that =this;//解决this:null问题
		if (this.gedan<=1) {
			for(let i=0;i<this.music.length;i++){
				axios
					.get('https://api.imjad.cn/cloudmusic/?type=detail&id='+this.music[i])
					.then(response => (//在数组的底部增加新元素
					   that.gedan.push({id:response.data.songs[0].id,name:response.data.songs[0].al.name})
					     ))
					}
			$("#ge_dan").slideToggle("slow");
		}else{
			$("#ge_dan").slideToggle("slow");
		}
		$(".list_ge").toggleClass("red");
	},
	listfun(id){//点击列表的播放时
		this.axiosmu(id);
	}

shou()展示与隐藏音乐播放控件的函数

gelist()中使用.push将获取到的歌曲数据存放到对应的内容中!

listfun()对展示出的歌曲列表点击进行切换歌曲

总结(重点记录)

1:利用 player.paused 可知道当前音乐是否在播放
let player = document.getElementById(‘xqt’);
if(player.paused){
暂停中
}else{
播放中
}

2:音乐播放
player.play();

3:音乐暂停
player.pause();

4:为某元素增加class
$(“.glyphicon-play”).addClass(“glyphicon-pause”);

5:为某元素移除class
$(“.zan_an”).removeClass(“zan_an_au”);

6:利用只执行一次的延迟定时器达到下一首播放功能
setTimeout(function () {that.xia_bo();},1000)

7:axios 通过API获取歌曲信息并整合
axios.all([this.getUserAccount(numb), this.getUserPermissions(numb)])//并发获取

8:将获取到的数据存放在数组中的对象
that.gedan.push({id:response.data.songs[0].id,name:response.data.songs[0].al.name})

标签