第十三周之QQ音乐移动端项目实战代码

QQ音乐移动端项目实战代码:

  • html代码:
     
     
     
         
         
         QQ音乐实战
         
         
     
     
     

    天空
    朴信惠

  • less代码:
     @import "reset.less";
     @import (reference)"public.less";
     html,body{
       width: 100%;
       height: 100%;
     }
     .musicBox{
       width: 100%;
       height: 100%;
       position: relative;
       .musicbg{
         width: 100%;
         height: 100%;
         position: absolute;
         left: 0;
         top: 0;
         z-index: -2;
         background: url("../img/piao.jpg") no-repeat center;
         background-size: cover;
         -webkit-filter: blur(5px);
         filter: blur(5px);
       }
       .musicshadow{
         width: 100%;
         height: 100%;
         position: absolute;
         left: 0;
         right: 0;
         z-index: -1;
         background-color: rgba(1,1,1,.3);
       }
     }
     //header
     header{
       padding: .3rem;
       color: @color-white;
       background-color: rgba(0,0,0,.3);
       .h-left{
         float: left;
         >img{
           float: left;
           width: 1.2rem;
           height: 1.2rem;
           margin-right: .4rem;
         }
         >p{
           float: left;
           font-size: .35rem;
           >span{
             line-height: .63rem;
           }
         }
       }
       .h-right{
         float: right;
         width: .8rem;
         height: .8rem;
         border-radius: 50%;
         border: 1px solid @color-white;
         box-sizing: border-box;
         margin-top: .2rem;
         margin-right: .1rem;
         position: relative;
         cursor: pointer;
         outline: none;
         .hr-play,.hr-pause{
           position: absolute;
           width: .4rem;
           height: .4rem;
           left: 50%;
           top:50%;
           margin-top: -.2rem;
           margin-left: -.2rem;
         }
         .hr-play{
           .spriteFn(@x:-.4rem,@y:-1.3rem);
         }
         .hr-pause{
           .spriteFn(@x:-.4rem,@y:-.36rem);
           display: none;
         }
       }
     }
     //main
     .main{
       margin: .4rem .2rem;
       overflow: hidden;
       position: relative;
       .lyc{
         position: absolute;
         transition: all 1s;
         >p{
           text-align: center;
           font-size: .32rem;
           line-height: .84rem;
           color: darken(@color-white,20%);
         }
         >p.active{
           color:@color-green;
         }
       }
     }
     //footer
     footer{
       margin: 0 .3rem;
       height: 3rem;
       color: darken(@color-white,10%);
       .storage{
         height: .8rem;
         >p{
           width: .6rem;
           height: .6rem;
           .spriteFn(@x:-2.185rem,@y:-.285rem);
           border-radius: 50%;
           border: 1px solid red;
           box-sizing: border-box;
           float: right;
           margin-top: .1rem;
         }
       }
       >audio{
         position: absolute;
       }
       .progressWrap{
         height: .8rem;
         font-size: .24rem;
         line-height: .8rem;
         text-align: center;
         .current{
           width: 12%;
           float: left;
         }
         .progress{
           width: 70%;
           height: .1rem;
           display: inline-block;
           vertical-align: .03rem;
           border-radius: .05rem;
           background-color: darken(@color-white,10%);
           position: relative;
           .time-line{
             position: absolute;
             height: 100%;
             border-radius: .05rem;
             background-color: @color-green;
           }
         }
         .duration{
           width: 12%;
           float: right;
         }
       }
       .download{
         width: 4.9rem;
         height: 1rem;
         line-height: 1rem;
         font-size: .36rem;
         margin: 0 auto;
         border-radius: .5rem;
         background-color: darken(@color-green,2%);
         text-align: center;
         position: relative;
         &::after{
           position: absolute;
           width: .74rem;
           height: .74rem;
           top: 50%;
           left: .16rem;
           margin-top: -.37rem;
           content: "";
           .spriteFn2();
         }
         >a{
           color: @color-white;
           font-weight: 700;
         }
       }
     }
    
  • JS代码:
     //添加拉伸事件
     $(window).on("resize",resizeTo).trigger("resize");
     var $htmlFont;
     function resizeTo() {
         //计算不同屏幕下html的fontSize值
         var $screenWidth=$(window).width();
         var $sjWidth=640;
         var $sjFont=100;
         //当屏幕宽度大于640px时,让$screenWidth值为640px,则计算出来的fontSize值一直为100px;
         //保证了屏幕中的rem值稳定,不会再随着屏幕改变而改变;
         if($screenWidth>$sjWidth){
             $screenWidth=$sjWidth;
             $("html").css({
                 width:$sjWidth,
                 margin: "0 auto"
             });
         }
         $htmlFont=$screenWidth/$sjWidth*$sjFont;
         $("html").css("fontSize",$htmlFont);
         //1 计算不用屏幕下的main歌词区域的高度
         //注意:在jQuery中$().height()拿到的高度不包含padding和边框,而zpeto中包含;
         //在jQuery中用$().outerHeight()可以拿到包含padding和边框的高度,但是zpeto中不支持此属性;
         var $screenH=$(window).height();
         var $mainH=$screenH-$("header").height()-$("footer").height()-0.8*$htmlFont-0.6*$htmlFont;//jQuery引入后,会覆盖zpeto;
         $(".main").css("height",$mainH);
     }
     //2 获取后台歌词数据,转换成需要的格式通过订阅式发布输出;
     var data=[],
         $id=0;
     //ajax获取数据,经过转化后,获取数组,然后通过jQuery中的订阅发布传入数据;
     var musicRender=(function () {
         return {
             init:function () {
                 $.ajax({
                     url:"data/lyc.txt",
                     dataType:"text",
                     type: "get",
                     success: function (result) {
                         var ary=result.split("\\n");//\n需要转义符,将获取的字符串数据,分割为数组;
                         var reg=/\[(\d{2})\:(\d{2})\.(?:\d{2})\](\D+)/g;//通过小分组拿到分,秒,文字;
                         //forEach方法,遍历数组,第一项为数组元素内容,第二项为数组元素的索引值
                         ary.forEach(function (item,index) {
                             //item为每一项的字符串,通过replace方法配合正则,进行逐一匹配操作;
                             item.replace(reg,function () {
                                 data.push({
                                     minute:arguments[1],
                                     seconds: arguments[2],
                                     lyc:arguments[3],
                                     id:$id
                                 })
                             });
                             $id++;
                         });
                         callbacks.fire(data);//向订阅发布传入数据
                     }
                 })
             }
         }
     })();
     musicRender.init();
     
     //3 jQuery中的订阅发布,获取歌词数据,插入页面
     var callbacks=$.Callbacks(),
         $lyc=$(".main .lyc"),
         $current=$("footer .progressWrap .current"),
         $duration=$("footer .progressWrap .duration");
     //获取媒体变量
     var oAudio=$("audio")[0],
         $btn=$(".h-right"),
         $hr_play=$(".hr-play"),
         $hr_pause=$(".hr-pause");
     //获取定时器变量
     var timer=null;
     //获取进度条元素
     var $time_line=$(".progress .time-line");
     //订阅式绑定方法;获取传入的数据,绑定在页面中;
     callbacks.add(function (data1) {
         //此时获得的数据为原生数组
         var str="";
         $.each(data1,function (index, item) {
             //字符串拼接,将数据放在自定义属性上;
             str+=`

    ${item.lyc}

    ` }); $lyc.html(str); }); //创建函数,用于转化时间格式 function timeFormat(time){ var min=Math.floor(time/60);//分钟用向下取整; var sec=Math.ceil(time%60);//秒用向上取整;这样会让歌词比音乐快一些; //判断当秒数为60时,变为0,分钟加等1; if(sec===60){ sec=0; min+=1; } min=min<10?"0"+min:""+min;//字符串拼接;得到的是字符串; sec=sec<10?"0"+sec:""+sec; return min+":"+sec; } //4 进入页面歌曲播放;获取音频的当前时间,控制歌词更新 callbacks.add(function () { oAudio.play();//加载页面后,歌词立刻播放; //拿到当前音频对象的总时间,为总秒数;转化格式后赋给$duratoin oAudio.addEventListener("canplay",function () { $duration.html(timeFormat(oAudio.duration)); /*oAudio.addEventListener("timeupdate",fn1)//每隔0.3s触发一次,可以替换定时器;*/ timer=setInterval(fn1,1000);//开启定时器,不断获取新的currentTime }) }); function fn1() { //获取当前的音乐时间,赋值在$current中; var currentTime=timeFormat(oAudio.currentTime); $current.html(currentTime); //通过获取的当前时间值,进行筛选p元素身上的自定义属性;进而控制相对应的文字变色显示; var minute=currentTime.split(":")[0]; var seconds=currentTime.split(":")[1]; //利用filter过滤器,通过属性判断,过滤选择; var targetP=$lyc.children("p").filter(`[data-minute="${minute}"]`).filter(`[data-seconds="${seconds}"]`); //将获取的p添加active类名;其他的兄弟元素删除类名; targetP.addClass("active").siblings().removeClass("active"); //歌词的移动,通过给lyc添加定位,控制其top值的变化 var indexP=targetP.index();//通过索引值获取哪个p的时候,开始运动; if(indexP>=2){ $lyc.css("top",-(indexP-2)*0.84*$htmlFont); } //进度条的设置:设置time-line的宽度占progress的宽度百分比 var tlW=Number(oAudio.currentTime/oAudio.duration*100)+"%"; //$time_line.css("width",tlW); $time_line.animate({ width: tlW }); //当前时间等于总时间时,停止定时器,按钮变为pause; if(oAudio.currentTime===oAudio.duration){ clearInterval(timer); oAudio.pause(); $hr_pause.show(); $hr_play.hide(); } } //5 播放和暂停的制作; callbacks.add(function () { $btn.on("click",function () {//在移动端不添加click时间,添加tap事件 clearInterval(timer); //在音频play播放时,oAudio.paused返回false值; if(oAudio.paused){ fn1(); timer=setInterval(fn1,1000); oAudio.play(); $hr_play.show(); $hr_pause.hide(); }else{ oAudio.pause(); $hr_pause.show(); $hr_play.hide(); } }) });

你可能感兴趣的:(第十三周之QQ音乐移动端项目实战代码)