一.话不多,先看效果:
视频B站效果演示地址~
https://www.bilibili.com/video/BV12y4y1g71S
这是个单页面音乐播放器,只用到了 html+css 与很基础的vue语法,所以适合初学者,看一看10分钟就会了~
二.详细制作步骤(完整代码在最后):
1.第一步当然是定义标签,对于每一个标签的作用注释都写得清清楚楚啦~:
<!-- 最底层的盒子 -->
<div class="container" id="container">
<!-- 头部区域盒子 -->
<div class="top">
<!-- 搜索框 -->
<input type="text" class="txt" v-model='query' @keyup.enter="searchMusic">
</div>
<!-- 歌曲列表区域 -->
<div class="list">
<ul>
<!-- 每个li是一首歌 -->
<li v-for="(item,index) in musicList " :key="index">
<a href="javascript:;" @click="playMusic(item.id)"></a>
{{item.name}}
</li>
</ul>
</div>
<!-- 中间区域 -->
<div class="middle">
<!-- 那个旋转的杆 -->
<img src="img/player_bar.png" alt="x" class="bar" :class="{playing:isPlay}">
<!-- 唱片 -->
<img src="img/disc.png" alt="x" class="disk" :class="{turn:isPlay}">
<!-- 唱片中间的海报 -->
<img :src="poster" class="poster">
</div>
<!-- 评论区 -->
<h5 class="commentTxt">热门评论:</h5>
<div class="comment">
<ul>
<!-- 每条评论 -->
<li v-for="(item,index) in comment" :key="index">
<!-- 头像 -->
<img :src="item.user.avatarUrl" alt="" width="50px" height="50px">
<!-- 网名 -->
<h3>{{item.user.nickname}}</h3>
<!-- 评论内容 -->
<p> {{item.content}}</p>
</li>
</ul>
</div>
<!-- 播放器进度条 -->
<audio class="music" @play="play" @pause="pause" :src="url" controls autoplay loop></audio>
</div>
标签里的vue语法解释(先看后面的js部分再看这里更好理解):
<input type="text" class="txt" v-model='query' @keyup.enter="searchMusic">
给这个标签 v-model='query’双向绑定数据query,@keyup.enter="searchMusic"绑定键盘回车事件,触发searMusic函数。
{{item.name}}
放内容,写在{{}}里。item相对于变量。
<li v-for="(item,index) in musicList " :key="index">
v-for="" 根据 musicList这个数组里元素的数量,动态生成多少个 li 。
<a href="javascript:;" @click="playMusic(item.id)"></a>
@click="playMusic(item.id)点击事件,触发playMusic(item.id)函数,并传参数。
<img src="img/player_bar.png" alt="x" class="bar" :class="{playing:isPlay}">
:class="{playing:isPlay},若isPlay值为真,playing这个选择器生效。
<img :src="poster" class="poster">
:src="poster"地址的值为自己定义的变量poster。
后面都是相似的了,以此类推~
2.定义css部分,对一些不常见的属性都会解释~:
1.整体区域:
/* 整体 */
.container{
width: 800px;
height: 500px;
background-color: rgba(248, 250, 252,0.3);
border-radius: 10px;
position: relative;
overflow: hidden;
}
border-radius: 10px; 角弧度
overflow: hidden;溢出隐藏
2.头部区域:
/* 头部 */
.top{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60px;
border-radius: 10px 10px 0 0;
background-image: linear-gradient(45deg,rgb(99, 202, 243),rgb(9, 253, 180),rgb(40, 106, 230));
z-index: 11;
}
.txt{
position: absolute;
top: 15px;
right: 50px;
width: 200px;
height: 30px;
outline: none;
border-radius: 15px;
border: none;
background-color: rgba(255, 255, 255,0.8);
padding: 0 20px 0 20px;
font-size: 13px;
}
background-image: linear-gradient(45deg,rgb(99, 202, 243),rgb(9, 253, 180),rgb(40, 106, 230));渐变背景色。
z-index: 11; 显示的级别,就是防止被别的元素遮挡,越大越上
border: none; 取消边框
3. 歌曲列表部分:
/* 歌曲列表 */
.list{
position: absolute;
left: 0;
top: 60px;
width: 200px;
height: 410px;
background-color: rgba(255, 255, 255,0.5);
}
.list>ul{
position: absolute;
width: 100%;
height: 100%;
overflow: auto;
}
.list>ul>li{
position: relative;
width: 100%;
height: 40px;
line-height: 40px;
font-family: 'fangsong';
font-size: 16px;
margin-top: 1px;
padding-left: 30px;
background-color: rgba(255, 255, 255, 0.9);
}
.list>ul>li>a{
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
width: 20px;
height: 20px;
background-image: url(img/play.png);
background-size: 100% 100%;
}
overflow: auto;如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
transform: translateY(-50%); 偏移,通常在定位50%后再偏移自身大小50%达到居中效果。
4. 中间部分:
/* 中间部分 */
.middle{
position: absolute;
left: 210px;
top: 60px;
width: 410px;
height: 410px;
}
.disk{
position: absolute;
width: 280px;
height: 280px;
left: 50%;
top: 50%;
transform: translate(-50%,-50%) rotateZ(0deg);
}
.bar{
position: absolute;
top: -10px;
left: 50%;
z-index:10;
transform-origin: 10px 10px;
/* 10 -25 */
transform: rotateZ(-25deg);
transition: all 1s;
}
.poster{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 160px;
height: 160px;
border-radius: 50%;
object-fit: cover;
}
transform: translate(-50%,-50%) rotateZ(0deg); translate(-50%,-50%)表偏移, rotateZ(0deg)表旋转。
transform-origin: 10px 10px; 旋转点就是绕哪个点旋转。
transition: all 1s; 过渡效果。
object-fit: cover; 保持图片原有尺寸比例。但部分内容可能被剪切。
5.评论区:
/* 评论 */
.comment{
position: absolute;
top: 80px;
right: -20px;
height: 410px;
width: 230px;
overflow: auto;
background-color: rgba(255, 255, 255,.4);
border-top-left-radius: 15px;
}
.commentTxt{
position: absolute;
top: 60px;
right: 110px;
width: 100px;
height: 20px;
line-height: 20px;
font-size: 12px;
color: rgb(0, 0, 0);
}
.comment>ul>li{
width: 210px;
min-height: 50px;
margin-top: 10px;
font-size: 13px;
padding: 5px;
text-align:justify;
}
.comment>ul>li>img{
border-radius: 50%;
display: inline-block;
vertical-align: middle;
}
.comment>ul>li>h3{
display: inline-block;
padding-left: 5px;
}
.comment>ul>li>p{
padding-top: 6px;
display: block;
text-indent: 2em;
}
vertical-align: middle;该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐。
text-indent: 2em;将段落的第一行缩进xxx像素:
6. 播放器进度条部分:
/* 进度条 */
.music{
position: absolute;
bottom: 0px;
left:0px;
width: 800px;
height: 34px;
outline: none;
background-color: rgb(241, 243, 244);
}
7. 杆和唱片转动
/* 杆和唱片转动 */
.playing{
transform: rotateZ(10deg);
}
.turn{
animation:turn 3s linear infinite;
}
@keyframes turn{
0%{
transform: translate(-50%,-50%) rotateZ(0deg);
}
100%{
transform: translate(-50%,-50%) rotateZ(360deg);
}
}
3. js部分,用vue语法写
1.先引入:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2.开始(详细请看注释):
歌曲主要调用的是网易云的公开API所得~
new Vue({
el:"#container",
data(){
return{
//搜索关键字
query:'',
//歌曲列表
musicList:[],
//当前歌曲地址
url:'',
//海报地址
poster:'./img/timg4.jpg',
//判断是否正在播放
isPlay: false,
//评论
comment:[]
}
},
methods:{
searchMusic(){
// 判断搜索框有没有字
if(this.query==''){
//没有自己返回
return;
}
// 发送请求获得数据
axios({
url:'https://autumnfish.cn/search',
method:'get',
params:{
keywords:this.query
}
}).then(res=>{
//把获取数据传给musicList数组,可以通过 console.log(res);查看自己想要的数据
this.musicList = res.data.result.songs;
})
},
playMusic(id){
//获得歌曲的url
axios({
url:'https://autumnfish.cn/song/url',
method:'get',
params:{
id:id
}
}).then(res=>{
// 将当前歌曲地址设置为这个
this.url = res.data.data[0].url;
})
//获取歌曲海豹
axios({
url:'https://autumnfish.cn/song/detail',
method:'get',
params:{
ids:id
}
}).then(res=>{
// 把图片地址纯存在poster数组
this.poster=res.data.songs[0].al.picUrl
})
//获取评论
axios({
url:'https://autumnfish.cn/comment/hot',
method:'get',
params:{
type:0,
id:id
}
}).then(res=>{
// 把评论的数据存在comment数组,包括头像,网名等等,可以通过 console.log(res);查看自己想要的数据
this.comment=res.data.hotComments
})
},
// 歌曲是正在播放触发
play(){
this.isPlay = true;
},
// 歌曲是停止触发
pause(){
this.isPlay = false;
}
}
})
三. 完整代码(需要素材与源文件的私信或在评论区留下邮箱,我发你呀):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>music</title>
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* 背景图 */
.bj{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: -1000;
}
/* 整体 */
.container{
width: 800px;
height: 500px;
background-color: rgba(248, 250, 252,0.3);
border-radius: 10px;
position: relative;
overflow: hidden;
}
/* 头部 */
.top{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60px;
border-radius: 10px 10px 0 0;
background-image: linear-gradient(45deg,rgb(99, 202, 243),rgb(9, 253, 180),rgb(40, 106, 230));
z-index: 11;
}
.txt{
position: absolute;
top: 15px;
right: 50px;
width: 200px;
height: 30px;
outline: none;
border-radius: 15px;
border: none;
background-color: rgba(255, 255, 255,0.8);
padding: 0 20px 0 20px;
font-size: 13px;
}
/* 歌曲列表 */
.list{
position: absolute;
left: 0;
top: 60px;
width: 200px;
height: 410px;
background-color: rgba(255, 255, 255,0.5);
}
.list>ul{
position: absolute;
width: 100%;
height: 100%;
overflow: auto;
}
.list>ul>li{
position: relative;
width: 100%;
height: 40px;
line-height: 40px;
font-family: 'fangsong';
font-size: 16px;
margin-top: 1px;
padding-left: 30px;
background-color: rgba(255, 255, 255, 0.9);
}
.list>ul>li>a{
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
width: 20px;
height: 20px;
background-image: url(img/play.png);
background-size: 100% 100%;
}
/* 中间部分 */
.middle{
position: absolute;
left: 210px;
top: 60px;
width: 410px;
height: 410px;
}
.disk{
position: absolute;
width: 280px;
height: 280px;
left: 50%;
top: 50%;
transform: translate(-50%,-50%) rotateZ(0deg);
}
.bar{
position: absolute;
top: -10px;
left: 50%;
z-index:10;
transform-origin: 10px 10px;
/* 10 -25 */
transform: rotateZ(-25deg);
transition: all 1s;
}
.poster{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 160px;
height: 160px;
border-radius: 50%;
object-fit: cover;
}
/* 评论 */
.comment{
position: absolute;
top: 80px;
right: -20px;
height: 410px;
width: 230px;
overflow: auto;
background-color: rgba(255, 255, 255,.4);
border-top-left-radius: 15px;
}
.commentTxt{
position: absolute;
top: 60px;
right: 110px;
width: 100px;
height: 20px;
line-height: 20px;
font-size: 12px;
color: rgb(0, 0, 0);
}
.comment>ul>li{
width: 210px;
min-height: 50px;
margin-top: 10px;
font-size: 13px;
padding: 5px;
text-align:justify;
}
.comment>ul>li>img{
border-radius: 50%;
display: inline-block;
vertical-align: middle;
}
.comment>ul>li>h3{
display: inline-block;
padding-left: 5px;
}
.comment>ul>li>p{
padding-top: 6px;
display: block;
text-indent: 2em;
}
/* 进度条 */
.music{
position: absolute;
bottom: 0px;
left:0px;
width: 800px;
height: 34px;
outline: none;
background-color: rgb(241, 243, 244);
}
/* 杆和唱片转动 */
.playing{
transform: rotateZ(10deg);
}
.turn{
animation:turn 3s linear infinite;
}
@keyframes turn{
0%{
transform: translate(-50%,-50%) rotateZ(0deg);
}
100%{
transform: translate(-50%,-50%) rotateZ(360deg);
}
}
</style>
</head>
<body>
<video src="./video.mp4" class="bj" muted autoplay loop ></video>
<div class="container" id="container">
<!-- 头部 -->
<div class="top">
<input type="text" class="txt" v-model='query' @keyup.enter="searchMusic">
</div>
<div class="list">
<ul>
<li v-for="(item,index) in musicList " :key="index">
<a href="javascript:;" @click="playMusic(item.id)"></a>
{{item.name}}
</li>
</ul>
</div>
<div class="middle">
<!-- 杆 -->
<img src="img/player_bar.png" alt="x" class="bar" :class="{playing:isPlay}">
<!-- 唱片 -->
<img src="img/disc.png" alt="x" class="disk" :class="{turn:isPlay}">
<!-- 海报 -->
<img :src="poster" class="poster">
</div>
<h5 class="commentTxt">热门评论:</h5>
<div class="comment">
<ul>
<li v-for="(item,index) in comment" :key="index">
<img :src="item.user.avatarUrl" alt="" width="50px" height="50px">
<h3>{{item.user.nickname}}</h3>
<p> {{item.content}}</p>
</li>
</ul>
</div>
<audio class="music" @play="play" @pause="pause" :src="url" controls autoplay loop></audio>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
el:"#container",
data(){
return{
//搜索关键字
query:'',
//歌曲列表
musicList:[],
//当前歌曲地址
url:'',
//海报
poster:'./img/timg4.jpg',
//判断是否正在播放
isPlay: false,
//评论
comment:[]
}
},
methods:{
searchMusic(){
if(this.query==''){
return;
}
axios({
url:'https://autumnfish.cn/search',
method:'get',
params:{
keywords:this.query
}
}).then(res=>{
this.musicList = res.data.result.songs;
})
},
playMusic(id){
axios({
url:'https://autumnfish.cn/song/url',
method:'get',
params:{
id:id
}
}).then(res=>{
this.url = res.data.data[0].url;
})
axios({
url:'https://autumnfish.cn/song/detail',
method:'get',
params:{
ids:id
}
}).then(res=>{
this.poster=res.data.songs[0].al.picUrl
})
axios({
url:'https://autumnfish.cn/comment/hot',
method:'get',
params:{
type:0,
id:id
}
}).then(res=>{
this.comment=res.data.hotComments
})
},
play(){
this.isPlay = true;
},
pause(){
this.isPlay = false;
}
}
})
</script>
</body>
</html>
四.总结:
这样子就完成了~
再说一遍,需要素材与源文件的私信或在评论区留下你的邮箱,我发你呀,可以对比源码和文章注释学习~
对了,夏目友人帐大家看了吗,又被治愈了~