在这篇文章[js高手之路]打造通用的匀速运动框架中,封装了一个匀速运动框架,我们在这个框架的基础之上,加上缓冲运动效果,然后用运动框架来做幻灯片(上下,左右),效果如下:【选择器用的是html5的,你的浏览器需要支持html5新选择器,才能看见效果额】
- 1
- 2
- 3
- 4
- 5
缓冲运动通常有两种常见的表现:比如让一个div从0运动到500,一种是事件触发的时候,速度很快, 一种是事件触发的时候慢,然后慢慢加快.我们来实现先块后慢的,常见的就是开车,比如刚从高速路上下来的车,就是120km/小时,然后进入匝道,变成40km/时. 或者40km/小时进入小区,最后停车,变成0km/小时. 从120km/小时->40km/小时, 或者40km->0km/小时,都是速度先块后慢,这种运动怎么用程序来表示呢?
可以用目标距离( 500 ) - 当前距离( 200 ) / 一个系数( 比如12 ),就能达到速度由块而慢的变化,当前距离在起点,分子(500 - 0 )最大,所以速度最大,如果当前距离快要接近500,分子最小,除完之后的速度也是最小。
1 <style> 2 div{ 3 200px; 4 height: 200px; 5 background:red; 6 position: absolute; 7 left: 0px; 8 } 9 </style> 10 <script> 11 window.onload = function(){ 12 var oBtn = document.querySelector( "input" ), 13 oBox = document.querySelector( '#box' ), 14 speed = 0, timer = null; 15 oBtn.onclick = function(){ 16 timer = setInterval( function(){ 17 speed = ( 500 - oBox.offsetLeft ) / 8; 18 oBox.style.left = oBox.offsetLeft + speed + 'px'; 19 }, 30 ); 20 } 21 } 22 </script> 23 </head> 24 <body> 25 <input type="button" value="动起来"> 26 <div id="box"></div> 27 </body>
你会发现,速度永远都在0.375这里停着,获取到的当前的距离停在497px? 这里有个问题,我们的div不是停在497.375px吗,怎么获取到的没有了后面的小数0.375呢?计算机在处理浮点数会有精度损失。我们可以单独做一个小测试:
1 <div id="box" style="position:absolute;left:30.2px;200px;height:300px;background:red;"></div> 2 <script> 3 var oBox = document.querySelector( '#box' ); 4 alert( oBox.offsetLeft ); 5 </script>
你会发现这段代码获取到左偏移是30px而不是行间样式中写的30.2px。因为在获取当前位置的时候,会舍去小数,所以速度永远停在0.375px, 位置也是永远停在497,所以,为了到达目标,我们就得把速度变成1,对速度向上取整( Math.ceil ),我们就能把速度变成1,div也能到达500
1 oBtn.onclick = function(){ 2 timer = setInterval( function(){ 3 speed = ( 500 - oBox.offsetLeft ) / 8; 4 if( speed > 0 ) { 5 speed = Math.ceil( speed ); 6 } 7 console.log( speed, oBox.offsetLeft ); 8 oBox.style.left = oBox.offsetLeft + speed + 'px'; 9 }, 30 ); 10 }
第二个问题,如果div的位置是在900,也就是说从900运动到500,有没有这样的需求呢? 肯定有啊,轮播图,从右到左就是这样的啊。
1 <style> 2 #box{ 3 200px; 4 height: 200px; 5 background:red; 6 position: absolute; 7 left: 900px; 8 } 9 </style> 10 <script>// <![CDATA[ 11 window.onload = function(){ 12 var oBtn = document.querySelector( "input" ), 13 oBox = document.querySelector( '#box' ), 14 speed = 0, timer = null; 15 oBtn.onclick = function(){ 16 timer = setInterval( function(){ 17 speed = ( 500 - oBox.offsetLeft ) / 8; 18 if( speed > 0 ) { 19 speed = Math.ceil( speed ); 20 } 21 oBox.style.left = oBox.offsetLeft + speed + 'px'; 22 }, 30 ); 23 } 24 } 25 // ]]></script> 26 </head> 27 <body> 28 <input type="button" value="动起来"> 29 <div id="box"></div> 30 </body>
1 oBtn.onclick = function(){ 2 timer = setInterval( function(){ 3 speed = ( 500 - oBox.offsetLeft ) / 8; 4 if( speed > 0 ) { 5 speed = Math.ceil( speed ); 6 }else { 7 speed = Math.floor( speed ); 8 } 9 console.log( speed, oBox.offsetLeft ); 10 oBox.style.left = oBox.offsetLeft + speed + 'px'; 11 }, 30 ); 12 }
然后我们把这个缓冲运动整合到匀速运动框架,就变成:
1 function css(obj, attr, value) { 2 if (arguments.length == 3) { 3 obj.style[attr] = value; 4 } else { 5 if (obj.currentStyle) { 6 return obj.currentStyle[attr]; 7 } else { 8 return getComputedStyle(obj, false)[attr]; 9 } 10 } 11 } 12 13 function animate(obj, attr, fn) { 14 clearInterval(obj.timer); 15 var cur = 0; 16 var target = 0; 17 var speed = 0; 18 obj.timer = setInterval(function () { 19 var bFlag = true; 20 for (var key in attr) { 21 if (key == 'opacity ') { 22 cur = css(obj, 'opacity') * 100; 23 } else { 24 cur = parseInt(css(obj, key)); 25 } 26 target = attr[key]; 27 speed = ( target - cur ) / 8; 28 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); 29 if (cur != target) { 30 bFlag = false; 31 if (key == 'opacity') { 32 obj.style.opacity = ( cur + speed ) / 100; 33 obj.style.filter = "alpha(opacity:" + ( cur + speed ) + ")"; 34 } else { 35 obj.style[key] = cur + speed + "px"; 36 } 37 } 38 } 39 if (bFlag) { 40 clearInterval(obj.timer); 41 fn && fn.call(obj); 42 } 43 }, 30 ); 44 }
有了这匀速运动框架,我们就来做幻灯片:
上下幻灯片的html样式文件:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>slide - by ghostwu</title> 6 <link rel="stylesheet" href="css/slide3.css"> 7 <script src="js/animate.js"></script> 8 <script src="js/slide.js"></script> 9 </head> 10 <body> 11 <div id="slide"> 12 <div id="slide-img"> 13 <div id="img-container"> 14 <img src="./img/1.jpg" alt="" style="opacity:1;"> 15 <img src="./img/2.jpg" alt=""> 16 <img src="./img/3.jpg" alt=""> 17 <img src="./img/4.jpg" alt=""> 18 <img src="./img/5.jpg" alt=""> 19 </div> 20 </div> 21 <div id="slide-nums"> 22 <ul> 23 <li class="active"></li> 24 <li></li> 25 <li></li> 26 <li></li> 27 <li></li> 28 </ul> 29 </div> 30 </div> 31 </body> 32 </html>
slide3.css文件:
1 * { 2 margin: 0; 3 padding: 0; 4 } 5 li { 6 list-style-type: none; 7 } 8 #slide { 9 width: 800px; 10 height: 450px; 11 position: relative; 12 margin:20px auto; 13 } 14 #slide-img { 15 position: relative; 16 width: 800px; 17 height: 450px; 18 overflow: hidden; 19 } 20 #img-container { 21 position: absolute; 22 left: 0px; 23 top: 0px; 24 height: 2250px; 25 /*font-size:0px;*/ 26 } 27 #img-container img { 28 display: block; 29 float: left; 30 } 31 #slide-nums { 32 position: absolute; 33 right:10px; 34 bottom:10px; 35 } 36 #slide-nums li { 37 float: left; 38 margin:0px 10px; 39 background: white; 40 width: 20px; 41 height: 20px; 42 text-align: center; 43 line-height: 20px; 44 border-radius:10px; 45 text-indent:-999px; 46 opacity:0.6; 47 filter:alpha(opacity:60); 48 cursor:pointer; 49 } 50 #slide-nums li.active { 51 background: red; 52 }
animate.js文件:
1 function css(obj, attr, value) { 2 if (arguments.length == 3) { 3 obj.style[attr] = value; 4 } else { 5 if (obj.currentStyle) { 6 return obj.currentStyle[attr]; 7 } else { 8 return getComputedStyle(obj, false)[attr]; 9 } 10 } 11 } 12 13 function animate(obj, attr, fn) { 14 clearInterval(obj.timer); 15 var cur = 0; 16 var target = 0; 17 var speed = 0; 18 obj.timer = setInterval(function () { 19 var bFlag = true; 20 for (var key in attr) { 21 if (key == 'opacity ') { 22 cur = css(obj, 'opacity') * 100; 23 } else { 24 cur = parseInt(css(obj, key)); 25 } 26 target = attr[key]; 27 speed = ( target - cur ) / 8; 28 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); 29 if (cur != target) { 30 bFlag = false; 31 if (key == 'opacity') { 32 obj.style.opacity = ( cur + speed ) / 100; 33 obj.style.filter = "alpha(opacity:" + ( cur + speed ) + ")"; 34 } else { 35 obj.style[key] = cur + speed + "px"; 36 } 37 } 38 } 39 if (bFlag) { 40 clearInterval(obj.timer); 41 fn && fn.call(obj); 42 } 43 }, 30 ); 44 }
slide.js文件:
1 window.onload = function () { 2 function Slide() { 3 this.oImgContainer = document.getElementById("img-container"); 4 this.aLi = document.getElementsByTagName("li"); 5 this.index = 0; 6 } 7 8 Slide.prototype.bind = function () { 9 var that = this; 10 for (var i = 0; i < this.aLi.length; i++) { 11 this.aLi[i].index = i; 12 this.aLi[i].onmouseover = function () { 13 that.moveTop( this.index ); 14 } 15 } 16 } 17 18 Slide.prototype.moveTop = function (i) { 19 this.index = i; 20 for( var j = 0; j < this.aLi.length; j++ ){ 21 this.aLi[j].className = ''; 22 } 23 this.aLi[this.index].className = 'active'; 24 animate( this.oImgContainer, { 25 "top" : -this.index * 450, 26 "left" : 0 27 }); 28 } 29 30 var oSlide = new Slide(); 31 oSlide.bind(); 32 33 }
1 * { 2 margin: 0; 3 padding: 0; 4 } 5 li { 6 list-style-type: none; 7 } 8 #slide { 9 width: 800px; 10 height: 450px; 11 position: relative; 12 margin:20px auto; 13 } 14 #slide-img { 15 position: relative; 16 width: 800px; 17 height: 450px; 18 overflow: hidden; 19 } 20 #img-container { 21 position: absolute; 22 left: 0px; 23 top: 0px; 24 width: 4000px; 25 } 26 #img-container img { 27 display: block; 28 float: left; 29 } 30 #slide-nums { 31 position: absolute; 32 right:10px; 33 bottom:10px; 34 } 35 #slide-nums li { 36 float: left; 37 margin:0px 10px; 38 background: white; 39 width: 20px; 40 height: 20px; 41 text-align: center; 42 line-height: 20px; 43 border-radius:10px; 44 text-indent:-999px; 45 opacity:0.6; 46 filter:alpha(opacity:60); 47 cursor:pointer; 48 } 49 #slide-nums li.active { 50 background: red; 51 }
js调用文件:
1 window.onload = function () { 2 function Slide() { 3 this.oImgContainer = document.getElementById("img-container"); 4 this.aLi = document.getElementsByTagName("li"); 5 this.index = 0; 6 } 7 8 Slide.prototype.bind = function () { 9 var that = this; 10 for (var i = 0; i < this.aLi.length; i++) { 11 this.aLi[i].index = i; 12 this.aLi[i].onmouseover = function () { 13 that.moveLeft( this.index ); 14 } 15 } 16 } 17 18 Slide.prototype.moveLeft = function (i) { 19 this.index = i; 20 for( var j = 0; j < this.aLi.length; j++ ){ 21 this.aLi[j].className = ''; 22 } 23 this.aLi[this.index].className = 'active'; 24 animate( this.oImgContainer, { 25 "left" : -this.index * 800 26 }); 27 } 28 29 var oSlide = new Slide(); 30 oSlide.bind(); 31 32 }