这是效果图,小编截下来的是静态图片,真是都是可以动的
不多说,直接上代码,注释都写在代码里清清楚楚
- 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;}}
}
- html
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Title</title><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">
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>-->
<!-- <p>就让光芒折射泪湿的瞳孔</p>--></div></main><footer class="footer" id="footer"><div class="progress" id="progress"><span class="current">00:00</span><span class="duration">00:00</span><div class="probg" id="probg"><div class="already"></div></div></div><a href="javascript:;" class="down" id="down">下载这首音乐</a></footer>
</section><!--
audio 是h5新增的标签,用来播放音频;
mp3
ogg
wav
m4a
// ...
(不支持amr格式的音频,npm上有一个库可以播放amr格式的音频)
如果有一天你接的需求中有音视频,要确认是什么格式,最好是mp3;如果不是mp3,谁来转(app或者服务端来转),如果前端来搞,体验会降级。
--><!--<audio src="img/myDream.m4a" controls autoplay preload="metadata"></audio>controls 启用audio的控制界面,如果不写,页面中将什么也不展示;autoplay 自动播放(iphone中不能用)preload 提前加载 auto 自动加载;none 不提前加载,播放时才加载;metadata 只加载音频的基本信息loop: 循环播放--><!--video的属性和audio基本相似,--><!--poster: 视频的封面图片<video src="http://www.w3school.com.cn/i/movie.ogg" poster="img/myDream.jpg" controls></video>--><!--视频流、音频流:不是一个具体的文件如果是播放流,一般服务端会提供给你一个 类似 rtmp://xxx.xx.com/dddd/xxx 的地址,把地址赋给audio和video的src属性;如果遇到不能用的情况,需要借助第三方的插件:video.js--><script src="js/zepto.min.js"></script><script src="js/index1.js"></script>
- 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的hightfunction 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+=`<p data-min="${item['start']}" data-sec="${item['end']}">${item['lyric']}</p>`})$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不是返回fasleif(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