手把手教你10分钟做一个单页面音乐播放器

一.话不多,先看效果:

视频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>

四.总结:

这样子就完成了~
再说一遍,需要素材与源文件的私信或在评论区留下你的邮箱,我发你呀,可以对比源码和文章注释学习~
对了,夏目友人帐大家看了吗,又被治愈了~
在这里插入图片描述

其它:

在这里插入图片描述

(完)