zepto+less写QQ音乐播放界面,进度条同步,歌词同步高亮等等(带注释,可参考可直接使用)

这是效果图,小编截下来的是静态图片,真是都是可以动的
zepto+less写QQ音乐播放界面,进度条同步,歌词同步高亮等等(带注释,可参考可直接使用)_第1张图片
不多说,直接上代码,注释都写在代码里清清楚楚

  1. less
@sizeMan:100%;
//关键帧动画函数
.keyframes(@name:move,@content){
//  @name:动画名,@content:动画内容
  @keyframes @name {@content();}
}


html{
  font-size: 100px;
  height: @sizeMan;
}
body{
  height: @sizeMan;
}








.container{
  height:@sizeMan;
  position: relative;
  .backgroundImg,.bg{
    position: absolute;
    width: @sizeMan;
    height: @sizeMan;
    z-index: -2;
  }
  .backgroundImg{
    background: url("../img/myDream.jpg");
    background-size: cover;
    //滤镜:设置模糊度
    filter: blur(7px);
  }
  .bg{
    background-color: rgba(0,0,0,0.3);
  }
  //头部
  .header{
    width: @sizeMan;
    height: 2rem;
    background-color: rgba(0,0,0,.2);
    padding: .3rem;
    //padding不改变整盒宽高
    box-sizing: border-box;
    display: flex;
    color: white;
    //定义一个关键帧动画
    .keyframes(move,{0%{transform: rotate(0deg)} 100%{transform: rotate(360deg)}});
    img{
      width: 1.2rem;
      height: 1.2rem;
    }
    div{
      margin-left: 5px;
      p:nth-of-type(1){
        font-size: .45rem;
      }
    }
    .musicBtn{
      width: .6rem;
      height: .6rem;
      background: url("../img/music.svg") no-repeat;
      background-size: cover;
      position: relative;
      top: .3rem;
      left: 3.7rem;
    &.select{
      //调用关键帧动画
      animation: move 1s linear 0s infinite;
    }
    }
  }
  //主体
  .main{
    height: 9.1rem;
    padding: .2rem;
    color: rgba(255,255,255,.5);
    font-size: .4rem;
    overflow: hidden;
    box-sizing: border-box;
    position: relative;
    letter-spacing: .04rem;
    .wrapper{
      width: @sizeMan;
      position: absolute;
      top: 0;
      left: 0;
    }
    p{
      width: @sizeMan;
      height: .8rem;
      text-align: center;
      line-height: .8rem;
      &.select{
        color: #31c27c;
      }
    }
  }
  //尾部
  .footer{
    color: white;
    box-sizing: border-box;
    .progress{
      width: @sizeMan;
      //.probg的父元素这里没有设置padding-top,所以后面设置.probg的margin的时候会传递给.progress
      //解决方法就是给一个overflow:hidden(原因就是父元素没有设置padding-top时子元素的margin-top会发生传递)
      overflow: hidden;
      position: relative;
      margin-bottom: .3rem;
      span{
        position: absolute;
        top: 0;
      }
      .current{
        left: .3rem;
      }
      .duration{
        right: .3rem;
      }
      .probg{
        width: 65%;
        margin: .15rem auto;
        background: rgba(2552,255,255,0.5);
        height: .04rem;
        .already{
          height: 100%;
          background-color: #31c27c;
          width: 10%;
        }
      }
    }
    a{
      display: block;
      width: 4.5rem;
      height: 1rem;
      background:url("../img/sprite_play.png") no-repeat 0.2rem -5.84rem #31c27c;
      background-size: .8rem 7rem;
      color: white;
      border-radius: .5rem;
      font-size: .4rem;
      text-align: center;
      line-height: 1rem;
      margin: auto;
    }
  }
}
  1. html
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Titletitle>
   <link rel="stylesheet" href="css/reset.min.css">
   <link rel="stylesheet/less" href="css/index1.less">
   <script>
   //手机屏幕适配
       ~(function (disn) {
               function getComputedFont() {
                   let winW=document.documentElement.clientWidth;
                   document.documentElement.style.fontSize=winW/disn*100+'px';
               }
               getComputedFont();
               window.addEventListener('resize',getComputedFont);
               window.addEventListener('orientationchange',getComputedFont);
           }
       )(750)
   script>
   <script src="js/less-2.5.3.min.js">script>
head>
<body>
<section class="container">
   <audio src="./img/myDream.mp3"  preload="none" id="audio">audio>
   
   <div class="backgroundImg">div>
   
   <div class="bg">div>
   <header class="header" id="header">
       <img src="img/myDream.jpg" alt="">
       <div class="song">
           <p>我的梦p>
           <p>张靓颖p>
       div>
       <a href="javascript:;" class="musicBtn" id="musicBtn">a>
   header>
   <main class="main" id="main">
       <div class="wrapper">








       div>
   main>
   <footer class="footer" id="footer">
       <div class="progress" id="progress">
           <span class="current">00:00span>
           <span class="duration">00:00span>
           <div class="probg" id="probg">
               <div class="already">div>
           div>
       div>
       <a href="javascript:;" class="down" id="down">下载这首音乐a>
   footer>
section>



   
   
   
   
   


   <script src="js/zepto.min.js">script>
   <script src="js/index1.js">script>
  1. js
~(function () {
   //获取元素
   let $header = $('.header'),
       $main = $('.main'),
       $footer = $('.footer'),
       $musicBtn = $('.musicBtn'),
       $wrapper = $('.wrapper'),
       $current = $('.current'),
       $duration = $('.duration'),
       $already = $('.already'),
       audio = document.getElementById('audio');
       progress=document.getElementsByClassName('progress')[0];
       //step标识当前播放哪条歌词,top标识屏幕显示的部分,autoPlayTime定时器返回值用来控制播放以及暂停时的歌词高亮和时间的及时更新
       let step=0, top=0, autoPlayTime,autoPlay;
   init();
   //主入口函数
   function init() {
       //起始运行一次computendMain方法适配用户的手机屏幕,同时绑定resize事件适屏幕
       computendMain();
       window.addEventListener('resize',computendMain);
       //给音符按钮绑定事件
       btnEvent();
       ajax();
   }
   //动态设置main部分的高度()
   //浏览器可视区域的高-header的hight-footer的hight
   function computendMain() {
       let winH=document.documentElement.clientHeight,//可视窗口的高度
           heiderH=$header[0].offsetHeight,//header的高度
           footerH=$footer[0].offsetHeight;//footer的高度
       //计算出main的高度(单位是px,我们要设置rem长度,所以还需要进行一次转换)
       let curH=(winH-heiderH-footerH)/parseFloat(document.documentElement.style.fontSize)-0.5;
       //设置main的height
       $main.css('height',curH+'rem');
   }
   //发送请求获取数据以及数据绑定
   function ajax() {
       //发送请求
       $.ajax({
           url:"./json/lyric.json",
           type:'GET',
           error(err){
               console.log(err);
           },
           success({lyric}){
               //绑定数据
               bindHTML(lyric);
           }
       });
       //绑定数据
       function bindHTML(lyric) {
           //替换歌词中的空格,(,),-等特殊符号
           lyric=lyric.replace(/&#(\d+);/g,(quan,num)=>{
               //为什么*1?上面捕获的是字符串类型的数字,*1将其转为数字类型的数字
               switch (num*1) {
                   case 32:
                       return ' ';
                   case 40:
                       return '(';
                   case 41:
                       return ')';
                   case 45:
                       return '-';
                   default:
                       return quan;
               }

           })
           //拼接字符串模板
           let str=``,ary=[];
           // 这个字符串不能使用split(';')来进行分割,那么怎么办?可以借用字符串的replace替换来巧妙遍历
           // [00:16.68]迎着痛把眼中所有梦
这是一句歌词,按这个格式来捕获遍历
           lyric.replace(/\[(\d+):(\d+).(?:\d+)\]([^&#]+)
/g,(quan,start,end,lyric)=>{
               ary.push({
                   start:start,end:end,lyric:lyric
               })
           });
           //遍历歌词数组动态添加歌词
           ary.forEach(item=>{
               str+=`

${item['start']}" data-sec="${item['end']}">${item['lyric']}

`
}) $wrapper.html(str); //歌词加载完毕开启播放和按钮旋转 audio.play(); $musicBtn.addClass('select'); } //实时检测播放进度 autoPlay=function () { //每过一秒检测一次 autoPlayTime=setInterval(changeTime,1000) }; autoPlay(); //检测播放进度更改歌词高亮以及播放时间的方法 function changeTime() { //解构出audio元素的currentTime当前时间和duration结束时间 let{currentTime, duration}=audio; if(currentTime>=duration){ //播放完毕 clearInterval(autoPlayTime); return; } //设置总时长 $duration.text(changeTime(duration)); //设置当前时长 $current.text(changeTime(currentTime)); //更改进度条 $already.css('width',currentTime/duration*100+'%'); //高亮歌词 let $ps=$('.wrapper>p'), [min,sec]=changeTime(currentTime).split(':'); $ps.each((idx,item)=>{ if(item.getAttribute('data-min')===min&&item.getAttribute('data-sec')===sec){ // $('.wrapper > p').filter(`[data-min="${min}"]`).filter(`[data-sec="${sec}"]`); // 这个filter方法是zepto中的方法,实现起来会更加的简单,上面的意思是先过滤data-min符合条件的出来 // 然后再过滤出data-sec符合条件的出来 $(item).addClass('select').siblings().removeClass('select'); step++; if(step>4){ top+=.8; $wrapper.css('top',-top+'rem'); } } }) //转换时间 function changeTime(time) { //获取分钟以及秒 let min = Math.floor(time / 60); let sec = Math.round(time - min * 60); //补零 min < 10 && (min = '0' + min); sec < 10 && (sec = '0' + sec); return `${min}:${sec}`; } } } //给音符绑定事件。top是zepto中提供的手机触摸方法 function btnEvent() { let deg;//用以记录暂停时按钮的旋转角度 $musicBtn.tap(function () { //判断当前是播放还是停止状态,audio自带的paused属性检测是否处于暂停状态,暂停状态返回true不是返回fasle if(audio.paused){ //暂停状态,play继续播放 audio.play(); //按钮添加旋转 $musicBtn.addClass('select'); //添加上次暂停角度 $musicBtn.css('transform',deg); //运行时间函数检测已放时间方法 autoPlay(); }else{ //播放状态,pause方法暂停播放 audio.pause(); //清除检测方法 clearInterval(autoPlayTime); //保存旋转的角度 deg=getComputedStyle($musicBtn[0])['transform']; //移除按钮旋转的动画 $musicBtn.removeClass('select'); } }) } })();

全部文件已上传百度云盘:https://pan.baidu.com/s/1We8dQfGrBQJIwiSkj_STgQ,提取码:pq8t

你可能感兴趣的:(javascript)