[js高手之路]封装运动框架实战左右与上下滑动的焦点轮播图

在这篇文章[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             width: 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>

 

 
 
但是,div并不会乖乖地停止在500px这个目标位置,最终却是停在497.375px,只要查看当前的速度,当前的值就知道原因了

 

 

你会发现,速度永远都在0.375这里停着,获取到的当前的距离停在497px? 这里有个问题,我们的div不是停在497.375px吗,怎么获取到的没有了后面的小数0.375呢?计算机在处理浮点数会有精度损失。我们可以单独做一个小测试:

1 <div id="box" style="position:absolute;left:30.2px;width: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             width: 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>

 

 

 
 
最后目标停在503.5px,速度这个时候是负值,最后速度停在-0.5,对于反方向的速度,我们就要把它变成-1,才能到达目标,所以用向下取整(Math.floor)
 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>
View Code

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 }
View Code

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 }
View Code

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 }
View Code
 
左右幻灯片只需要改下样式即可
样式文件:
 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 }
View Code

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 }
View Code

 

posted @ 2017-10-16 16:09  ghostwu  阅读(1268)  评论(2编辑  收藏  举报
Copyright ©2017 ghostwu