可控动画
<!DOCTYPE html> <html> <!-- 简述:做一个可控动画,能够根据用户输入判断是逐帧播放还是完全播放,同时也能够根据输入前进或者后退。 要点分析: 监听交互:单击,触摸,滚动等等 识别临界值:位移等。临界值内逐帧并且放弃交互时回退到交互前的状态;临界值外则动画完全播放。 动画:可在前进和后退之间切换(可通过传参);可逐帧播放(帧可以是小动画) 优化效率 相关交互: 下拉时:逐帧退和整节退 上拉时:逐帧前进和整节前进 放弃操作:超过临界值(动画完成)和未超过临界值(动画回退)。 动画关键点:帧和节都可进退,同时进退皆可控。 --> <head> <meta charset="UTF-8"> <title>可控动画</title> </head> <style> ul, li { list-style: none; padding: 0; margin: 0; } ul { font-size: 0; } .btn-wrap{ text-align: center; margin-top: 20px; } .window { width: 300px; height: 200px; overflow: hidden; margin: 60px auto; border: 1px solid red; } .canvas { width: 1200px; height: 200px; } .canvas img { height: 200px; width: 300px; } ul li { display: inline-block; width: 300px; text-align: center; background-color: greenyellow; } </style> <body> <div> <div class="btn-wrap"> <button id="move">逐帧前进</button> <button id="single-reverse">逐帧后退</button> <button id="play">整节前进</button> <button id="reverse">整节后退</button> </div> <div class="window"> <div class="canvas" id="main"> <ul> <li class="item"><img draggable="false" src="img/img1.jpg"></li> <li class="item"><img draggable="false" src="img/img2.jpg"></li> <li class="item"><img draggable="false" src="img/img3.jpg"></li> </ul> </div> </div> </div> </body> <script> //变量定义 var canvas = document.getElementsByClassName('canvas')[0], main=document.getElementById("main"),//画布元素,也就是移动主体。 items=document.getElementsByClassName('item'), item_len=items.length, value = false,//是否在临界值之外,true为在临界值之外,false为临界值之内。 key=false,//鼠标是否按下 index=0,//当前是第几节动画 reverse = false,//节动画是否反方向播放 single_reverse=false,//帧动画是否反方向播放 frameTime = 13,//帧与帧之间播放间隔 stepDistance = (300 / (3000 / 30)), //每次移动的小距离,也就是每帧位移,单位为像素。 stepDistanceSum = 0; //移动的总距离 //交互 //顺序播放 document.getElementById('play').onclick = function() { index++;//每单击一次播放一节 if(index>item_len){ index=0;//如果节动画完全播放完毕,从头开始播放 }; reverse = false; value = true; littleMove(index); }; //倒叙播放 document.getElementById('reverse').onclick = function() { index--;//每单击一次后退一节 if(index<0){ index=0; }; value = true; reverse = true; littleMove(index); }; //正向移动帧,没有实际意义,用于临界值之内的帧移动 document.getElementById('move').onclick = function() { value = false; reverse = false; single_reverse=false; littleMove(index); }; //反向移动帧,没有实际意义,用于临界值之内的帧后退 document.getElementById('single-reverse').onclick = function() { value = false; reverse = false; single_reverse=true; littleMove(index); }; main.onmousedown=function(e){ var e = e || event; key=true; }; main.onmouseup=function(){ key=false; }; main.addEventListener('mousemove',function(e){ var e = e || event; if(key){ //鼠标被按下 if(stepDistanceSum<50){ //并且小于临界值,一帧一帧播放动画 value = false; reverse = false; single_reverse=false; littleMove(index); }else{ //临界值之外,播放完整节动画 reverse = false; value = true; littleMove(index); } } }); //动画函数 function littleMove(index) { // console.log('进入littleMove函数'); if(!value) { if(stepDistanceSum<=300*(item_len-1)){ //临界值之内,每次交互移动一次 if((stepDistanceSum-(300*index))<300) {//如果小于300则一直可以帧移动 if(single_reverse){ stepDistanceSum -= stepDistance; canvas.style.marginLeft = -stepDistanceSum + 'px'; }else{ stepDistanceSum += stepDistance; canvas.style.marginLeft = -stepDistanceSum + 'px'; } } else { } }else{ clearInterval(interval); } } else { //临界值外,小节动画一次性播放完毕 var interval = setInterval(function() { if(stepDistanceSum<=300*(item_len-1)){//未超过边界 // console.log('边界之内'); if(stepDistanceSum%300==0){ clearInterval(interval); }; if(reverse) { if(stepDistanceSum<0){ clearInterval(interval); }else{ canvas.style.marginLeft = +stepDistanceSum + 'px'; console.log(stepDistanceSum); stepDistanceSum -= stepDistance; console.log(stepDistanceSum); } } else { canvas.style.marginLeft = -stepDistanceSum + 'px'; stepDistanceSum += stepDistance; } }else{//超过边界,从头开始 clearInterval(interval); stepDistanceSum=0; } }, frameTime) } }; </script> </html>