B站看完一位老师讲的vue项目(悦听),是一个音乐播放器,花了两天时间完成了这个项目,第一次将前几天学习的vue知识应用到项目中,虽然有些地方还需要完善,但是通过这几天的学习,无论是vue入门,还是对html、css知识的复习,都很有收获。之前,每次网页布局的时候,有很多次,仅仅改变了一个元素的属性,页面整体发生了“很奇怪”的变化,很有挫败感,这几天重新学习了css中有关文档流、浮动、定位、弹性盒字等知识,感觉豁然开朗。
前两天学习了vue,仅仅算是入门了,主要是一些vue指令和axios的使用,只是简单地使用vue指令做的小应用是本地应用的“小黑记事本”,结合axios做的网络应用有“天知道”和这篇文章要介绍的音乐播放器“悦听”,废话不多说,进入正题。。(如果功能有完善,后续更新…)

一、项目需求

主界面:
页面
mv界面:
mv界面

从上到下,分别是搜索栏、主体部分、音频进度条,主体部分从左到右分别是音乐列表、磁盘动画、留言列表。
主要功能有:
1.歌曲搜索:搜索栏中输入关键字,按下回车或者鼠标点击输入框后面的放大镜图标,返回给左侧音乐列表所有相关的歌曲名称。
2.歌曲播放:点击音乐列表中每条音乐前面的红色播放图标实现播放功能,下方进度条显示当前播放进度。
3.查看热评:歌曲播放的同时,右侧评论列表展示所有热评。
4.歌曲播放时的动画:歌曲播放的同时,磁盘中央封面改成相对应的专辑封面,上面的磁头旋转到磁盘上,歌曲暂停后,磁头再旋转回去。
5.mv播放:点击音乐列表中右侧的小电视图标,展现出四周由遮罩层包含的mv界面。
6.mv暂停:点击四周遮罩层,mv暂停,回到主界面。

二、相关接口

1.歌曲搜索接口
    请求地址:https://autumnfish.cn/search
    请求方法:get
    请求参数:keywords(查询关键字)
    响应内容:歌曲搜索结果
2.歌曲url获取接口
    请求地址:https://autumnfish.cn/song/url
    请求方法:get
    请求参数:id(歌曲id)
    响应内容:歌曲url地址
3.歌曲详情获取
	请求地址:https://autumnfish.cn/song/detail
    请求方法:get
    请求参数:ids(歌曲id)
    响应内容:歌曲详情(包括封面信息)
4.热门评论获取
   	请求地址:https://autumnfish.cn/comment/hot?type=0
    请求方法:get
    请求参数:id(歌曲id,地址中的type固定为0)
    响应内容:歌曲的热门评论
5.mv地址获取
    请求地址:https://autumnfish.cn/mv/url
    请求方法:get
    请求参数:id(mvid,为0表示没有mv)
    响应内容:mv的地址

三、代码实现

html:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>悦听</title>
		<link rel="stylesheet" href="my.css"/>
	</head>
	<body>
		<div class="wrap">
			<div class="play_wrap" id="player">
				<!--搜索栏-->
				<div class="search_bar">
					<div class="title">悦听</div>
					<div class="search">
						<input @keyup.enter="searchMusic" v-model="query" type="text" class="content" />
						<img @click="searchMusic" class="loupe" src="images/zoom.png" />
					</div>
				</div>
				
				<!--主体部分-->
				<div class="center_con">
					<div class="music_list">
						<ul class="music">
							<li v-for="(item,index) in musicName" class="music_li">
								<a @click="playMusic(item.id)" href="#">
									<img class="music_btn" src="./images/play.png" />
								</a>
								<span class="music_name">{{item.name}}</span>
								<span v-show="item.mvid!=0" class="mv_btn">
									<img @click="getMv(item.mvid)" class="mvtable" src="images/table2.png" />
								</span>
							</li>
						</ul>
					</div>
					<div>
						<img class="left_line" src="images/line.png" />
					</div>
					<div class="pic">
						<div class="top" :class="{playing:isPlaying}">
							<img class="player" src="images/player_bar.png" />
						</div>
						<div class="center">
							<img class="disc" src="images/disc.png" />
							<!--不能有两个src(一个默认的,一个是当前歌的封面),要用条件表达式-->
							<img :src="picUrl==''?'./images/cover.png':picUrl" class="cover"/>
						</div>
					</div>
					<div>
						<img class="right_line" src="images/line.png" />
					</div>
					<div class="comment_list_outer">
						<b class="comm">热门留言</b><br />
						<div class="comment_list">
							<ul class="comment">
								<li v-for="(item,index) in commentList" class="comment_li">
									<img class="user_pic" :src="item.user.avatarUrl" />
									<div class="comm_right">
										<b class="user_nickname">{{item.user.nickname}}</b><br />
										<span class="user_comm">{{item.content}}</span>
									</div>
								</li>
							</ul>
						</div>
					</div>
					
				</div>
				
				<!--播放进度音频-->
				<div class="audio_con">
					<audio :src="musicUrl" @play="play" @pause="pause" class="audio" autoplay controls loop></audio>
				</div>
				
				<!--视频-->
				<div class="video_con"  v-show="isShow">
					<!--ref-->
					<video ref='video' :src="mvUrl" autoplay controls loop></video>
					<div class="mask" @click="closeMv"></div>
				</div>
			</div>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
		<script src="my.js"></script>
	</body>
</html>

css:

*{
	margin: 0;
	padding: 0;
	list-style: none;
}
.wrap{
	
	width: 100vw;
	height: 100vh;
	overflow: hidden;
	background:url(./images/bg.jpg) no-repeat;
	background-size: 100% 100%;
}
.play_wrap{
	width: 800px;
	height: 520px;
	margin: 77px auto;
	
}
.search_bar{
	position: relative;
	z-index: 4;
	border-radius: 5px 5px 0 0;
	height: 60px;
	display: flex;
	background-color: dodgerblue;
}
.title{
	flex: 1;
	padding-top: 10px;
	padding-left: 15px;
	color: white;
	line-height:40px;
	font-size: 30px;
	font-family: "隶书";
}
.search{
	flex:1;
	line-height:60px;
	/*当flex:8的时候,为啥padding-left值越大,听字会被盖住,因为padding的值会影响整个div的可见区*/
	/*浏览器检察元素的宽高是可视区的宽高,包括边框、内边距、内容区,不包括外边框*/
	/*flex如果都设置成1,只是代表width之比是1:1*/
	/*当前的情况:(flex为1:1时)设两个弹性元素的width为x,则有2*x+padding-left=500-5px(悦听左边的边距)*/
	padding-left: 240px;
	/*background-color: blue;*/
}
.loupe{
	position: relative;
	top: -53px;
	left: 230px;
}
.content{
	border: none;
	outline: none;
	width: 250px;
	height: 30px;
	padding-left: 10px;
	border-radius: 15px;
}
.center_con{
	height: 445px;
	display: flex;
	background-color: rgb(255,255,255,.5);
}
.music_list{
	flex: 6;
	overflow-y: auto;
  	overflow-x: hidden;
}
.music_list::-webkit-scrollbar,.comment_list::-webkit-scrollbar{
  display: none;
}
.music{
	padding:5px;
}
.music_li:nth-of-type(odd){
	display: flex;
	padding: 3px;
	line-height: 30px;
	font-size: 12px;
}
.music_li:nth-of-type(even){
	display: flex;
	padding: 3px;
	line-height: 30px;
	font-size: 12px;
	background-color: rgba(240, 240, 240, 0.3);
}
.comment_li{
	display: flex;
	padding: 10px;
	line-height: 20px;
	font-size: 15px;
}
.music_btn{
	width: 17px;
	height: 17px;
	padding-top: 7px;
	flex:2 ;
}
.music_name{
	flex:5 ;
	margin-left: 12px;
}
.mv_btn{
	flex:2 ;
	/**/
	/*background: url("./images/table2.png");*/
}
.mvtable{
	padding-top: 10px;
	margin-left: 15px;
	width: 18px;
	height: 18px;
}
.left_line,.right_line{
	width: 1px;
	height: 440px;
}
.pic{
	flex: 12;
}
.player{
	position: absolute;
	top: 125px;
	left: 680px;
	z-index: 3;
	transform: rotate(-45deg);
  	transform-origin: 12px 12px;
  	transition: 1s;
}
.playing .player{
	transform: rotate(0);
}
.disc{
	position: absolute;
	width: 265px;
	height: 265px;
	top: 200px;
	left: 570px;
	z-index: 2;
}
.cover{
	position: absolute;
	width: 160px;
	height: 160px;
	top: 250px;
	left: 620px;
	z-index: 1;
	
}
.comment_list_outer{
	flex:6;
	padding: 8px;
}
.comment_list{
	height: 415px;
	overflow-y: auto;
  	overflow-x: hidden;
}
.user_pic{
	width: 40px;
	height: 40px;
	border-radius: 50%;
}
.comm_right{
	margin: 7px;
}
.user_comm{
	font-size: 12px;
	color: #666;
}
.audio_con{
	height: 35px;
	
}
.audio{
	outline: none;
	width: 800px;
	height: 45px;
	border-radius:0 0 5px 5px;
	background-color: rgb(241, 243, 244);;
}
.mask{
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 980;
  background-color: rgb(0,0,0,.8);
}
video{
  position: fixed;
  left:250px;
  top: -10px;
  width: 870px;
  height: 670px;
  /*transform: translateX(-50%);*/
  z-index: 990;
}

js:

var music=new Vue({
	el:"#player",
	data:{
		query:"",
		musicName:[],
		musicUrl:"",
		picUrl:"",
		commentList:[],
		mvUrl:"",
		isShow:false,
		isPlaying:false
	},
	methods:{
		searchMusic:function(){
			var that=this;
			axios.get("https://autumnfish.cn/search?keywords="+this.query)
			.then(
				function(res){
					that.musicName=res.data.result.songs;
//					console.log(res);
				})
			.catch(function(err){console.log(err);})
		},
		playMusic:function(musicId){
			var that=this;
			axios.get("https://autumnfish.cn/song/url?id="+musicId)
			.then(
				function(res){
					that.musicUrl=res.data.data[0].url;
				})
			.catch(function(err){console.log(err);})
			
			axios.get("https://autumnfish.cn/song/detail?ids="+musicId)
			.then(
				function(res){
					that.picUrl=res.data.songs[0].al.picUrl;
				})
			.catch(function(err){console.log(err);})
			
			axios.get("https://autumnfish.cn/comment/hot?type=0&id="+musicId)
			.then(
				function(res){
					console.log(res);
					that.commentList=res.data.hotComments;
				})
			.catch(function(err){console.log(err);})
		},
		getMv:function(mvid){
			var that=this;
			that.isShow=true;
			axios.get("https://autumnfish.cn/mv/url?id="+mvid)
			.then(
				function(res){
					that.mvUrl=res.data.data.url;
				})
			.catch(function(err){console.log(err);})
		},
		closeMv:function(){
			this.isShow=false;
			//$refs
			this.$refs.video.pause();
		},
		play:function(){
			this.isPlaying=true;
		},
		pause:function(){
			this.isPlaying=false;
		}
	}
})
Logo

前往低代码交流专区

更多推荐