用原生的javascript 实现一个无限滚动的轮播图

Posted 叶文翔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用原生的javascript 实现一个无限滚动的轮播图相关的知识,希望对你有一定的参考价值。

说一下思路:和我上一篇博客中用JQ去写的轮播图有相同点和不同点

相同点:

  • 首先页面布局是一样的
  • 同样是改变.inner盒子的位置去显示不同的图片

不同点:

  • 为了实现无限滚动需要多添加两张重复的图片
  • 左右切换和前面的方法有所不同,前面是获取当前的索引值乘以-600px当做位移距离,现在是需要获取当前.inner的位置来加上或者减去-600来实现

下面来一步步的去实现轮播图:

首先是html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    ul{
        list-style: none;
        position: absolute;
        bottom: 0;
        left: 175px;
    }
    ul li{
        float: left;
    }
    ul li a{
        display: block;
        width: 20px;
        height: 20px;
        border-radius: 50%;
        background-color: #ffbeaa;
        margin-left: 5px;
        opacity: 0.6;
    }
    ul li a.active{
        background-color: red;
    }
    .inner{
        width: 4200px;
        height: 400px;
        position: absolute;
    }
    .inner img{
        display: block;
        float: left;
    }
    .pic{
        height: 400px;
        width: 600px;
        overflow: hidden;
        position: relative;
    }
    .prev,.next{
        position: absolute;
        top: 190px;
        opacity: 0.6;
    }
    .next{
        right: 0;
    }
    </style>
    <script>
        
    </script>
</head>
<body>
    <div class="pic" id="pic">
        <div class="inner" id="inner" style="left:-600px;">
            <img src="img/5.jpg" alt="">
            <img src="img/1.jpg" alt="">
            <img src="img/2.jpg" alt="">
            <img src="img/3.jpg" alt="">
            <img src="img/4.jpg" alt="">
            <img src="img/5.jpg" alt="">
            <img src="img/1.jpg" alt="">
        </div>
        <ul id="ul">
            <li><a href="#" class="active" id="1"></a></li>
            <li><a href="#" id="2"></a></li>
            <li><a href="#" id="3"></a></li>
            <li><a href="#" id="4"></a></li>
            <li><a href="#" id="5"></a></li>
        </ul>
        <a href="#" class="prev" id="prev"><img src="img/slider-prev.png" alt=""></a>
        <a href="#" class="next" id="next"><img src="img/slider-next.png" alt=""></a>
    </div>
</body>
</html>

第一步添加左右点击切换:

<script>
        //文档加载完毕后执行函数
        window.onload=function(){
            var pic = document.getElementById("pic");
            var inner = document.getElementById("inner");
            var li = document.getElementById("ul").getElementsByTagName("a");
            var prev = document.getElementById("prev");
            var next = document.getElementById("next");
            //设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色
            var index = 1;
            //左点击事件
            prev.onclick = function(){
            //调用动画函数,传入正的600,为每次的偏移量
                animate(600);
            //设置索引的范围,不能小于1
                if(index==1){
                    index=5;
                }else{
                    index--;
                }
            //调用添加颜色函数
                showButton();
            }
            //右点击事件
            next.onclick = function(){
            //调用动画函数,传入负的600,为每次的偏移量
                animate(-600);
            //设置索引的范围,不能超过5    
                if(index==5){
                    index=1;
                }else{
                    index++;
                }
                showButton();
            }
            //动画函数,offset参数为偏移量
            function animate(offset){
            //获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子
                inner.style.left = parseInt(inner.style.left) + offset + "px";
            //判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px
                if(parseInt(inner.style.left) < -3000){
                    inner.style.left = -600 + "px";
                }
                if(parseInt(inner.style.left) > -600){
                    inner.style.left = -3000 + "px";
                }
            }
            //按钮添加颜色函数
            function showButton(){
            //遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类
                for(var i=0;i<li.length;i++){
                    if(li[i].className=="active"){
                        li[i].className="";
                        //移除后就没必要去循环了,做一个优化。
                        break;
                    }
                }
            //根据当前的index值,找到对应的a元素添加active类
                li[index-1].className="active";
            }    
        }
    </script>

需要注意的地方:

  1. 执行完毕inner.style.left = parseInt(inner.style.left) + offset + "px"; 后 inner.style.left的值为新位置的值,后面的判断需要用新的值去判断
  2. index的值为1-5,做成a元素的下标时需要 index-1
  3. 注意调用的showButton函数的位置,需要在得到index的值的后调用
  4. 需要给.inner盒子添加行内样式 style="left:-600px;",不添加出现inner.style.left获取不到值的情况
  5. 获取a元素不能 var li = document.getElementById("ul").getElementsByTagName("li").getElementsByTagName("a");去获取,因为getElementsByTagName("li")获取的是一个包含5个li的数组,需要加索引值,比如var li = document.getElementById("ul").getElementsByTagName("li")[0].getElementsByTagName("a");

第二步:添加五个按钮切换

 1 <script>
 2         //文档加载完毕后执行函数
 3         window.onload=function(){
 4             var pic = document.getElementById("pic");
 5             var inner = document.getElementById("inner");
 6             var li = document.getElementById("ul").getElementsByTagName("a");
 7             var prev = document.getElementById("prev");
 8             var next = document.getElementById("next");
 9             //设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色
10             var index = 1;
11             //左点击事件
12             prev.onclick = function(){
13             //调用动画函数,传入正的600,为每次的偏移量
14                 animate(600);
15             //设置索引的范围,不能小于1
16                 if(index==1){
17                     index=5;
18                 }else{
19                     index--;
20                 }
21             //调用添加颜色函数
22                 showButton();
23             }
24             //右点击事件
25             next.onclick = function(){
26             //调用动画函数,传入负的600,为每次的偏移量
27                 animate(-600);
28             //设置索引的范围,不能超过5    
29                 if(index==5){
30                     index=1;
31                 }else{
32                     index++;
33                 }
34                 showButton();
35             }
36             //动画函数,offset参数为偏移量
37             function animate(offset){
38             //获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子
39                 inner.style.left = parseInt(inner.style.left) + offset + "px";
40             //判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px
41                 if(parseInt(inner.style.left) < -3000){
42                     inner.style.left = -600 + "px";
43                 }
44                 if(parseInt(inner.style.left) > -600){
45                     inner.style.left = -3000 + "px";
46                 }
47             }
48             //按钮添加颜色函数
49             function showButton(){
50             //遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类
51                 for(var i=0;i<li.length;i++){
52                     if(li[i].className=="active"){
53                         li[i].className="";
54                         //移除后就没必要去循环了,做一个优化。
55                         break;
56                     }
57                 }
58             //根据当前的index值,找到对应的a元素添加active类
59                 li[index-1].className="active";
60             }
61             //遍历五个按钮
62             for(var i=0;i<li.length;i++){
63             //给五个按钮添加点击事件
64                 li[i].onclick=function(){
65                     //获取当前的id值
66                     var id = parseInt(this.getAttribute("id"));
67                     //减去原来的index值,乘以-600 得到偏移量,调用偏移函数
68                     var offset = (id-index) * -600;
69                     //调用偏移函数
70                     animate(offset);
71                     //把index的值更新
72                     index = id;
73                     //调用改变背景色函数
74                     showButton();
75                 }
76             }    
77         }
78     </script>

需要注意:

  1. 第72行 index = id 把index的值更新为当前的索引index。
  2. 因为id属性不是HTML自带的属性。不能li.style.id 这样去获取,而是使用getAttribute("id")方法,这个方法HTML自带属性和自定义属性都能获取

第三步:添加animate函数添加动画函数

 1 <script>
 2         window.onload=function(){
 3             var pic = document.getElementById("pic");
 4             var inner = document.getElementById("inner");
 5             var li = document.getElementById("ul").getElementsByTagName("a");
 6             var prev = document.getElementById("prev");
 7             var next = document.getElementById("next");
 8             var index = 1;
 9             //通过state的状态 来判断是否执行animate函数
10             var state = false;
11             prev.onclick = function(){
12                 //如果state=false 代表动画函数没有执行完毕,则此次点击无效
13                 if(state){
14                     return;
15                 }
16                 animate(600);
17                 if(index==1){
18                     index=5;
19                 }else{
20                     index--;
21                 }
22                 showButton();
23             }
24             next.onclick = function(){
25                 //如果state=false 代表动画函数没有执行完毕,则此次点击无效
26                 if(state){
27                     return;
28                 }
29                 animate(-600);
30                 if(index==5){
31                     index=1;
32                 }else{
33                     index++;
34                 }
35                 showButton();
36             }
37 
38             function animate(offset){
39                 //调用animate函数后 state的值变为true
40                 state = true;
41                 //动画执行总的时间
42                 var time = 300;
43                 //每次位移的间隔时间
44                 var interval = 10;
45                 //每次位移量
46                 var speed = offset/(time/interval);
47 
48                 var newLeft = parseInt(inner.style.left) + offset;
49                 //动画函数
50                 function go(){
52            if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){
53                         inner.style.left = parseInt(inner.style.left) + speed + "px";
54                         //通过延时定时器不断的去调用自身go函数。直到达到目标位置
55                         setTimeout(go,interval);
56                     }else{
57                         //达到目标位置后 state 状态变为 false
58                         state = false;
59                         //跟新.inner盒子的值为目标的位置
60                         inner.style.left = newLeft + "px";
61                         //盒子到达目标位置后做一个判断,如果跑到假的第一张图和第五张图上时,马上瞬间跑到真正的第一张图或者第五张图
62                         if(parseInt(inner.style.left) < -3000){
63                         inner.style.left = -600 + "px";
64                         }
65                         if(parseInt(inner.style.left) > -600){
66                         inner.style.left = -3000 + "px";
67                         }
68                     }
69                 }
70                 go();
71                 
72             }
73             function showButton(){
74                 for(var i=0;i<li.length;i++){
75                     if(li[i].className=="active"){
76                         li[i].className="";
77                         break;
78                     }
79                 }
80                 li[index-1].className="active";
81             }
82             for(var i=0;i<li.length;i++){
83                 li[i].onclick=function(){
84                     var id = parseInt(this.getAttribute("id"));
85                     var offset = (id-index) * -600;
86                     //如果state=false 代表动画函数没有执行完毕,则此次点击无效
87                     if(state){
88                     return;
89                     }    
90                     animate(offset);
91                     index = id;
92                     showButton();
93                 }
94             }    
95         }

做这个go函数我觉得是这个轮播图中最难的点,我经常有地方转不过弯来。

需要注意的地方:

  1. 每次位移一小段距离,终点怎么去判断,也就是什么时候会停止,.inner盒子只能往左边或者右边移动,点击next按钮 .inner往左边移动,是添加一个负值距离,点击prev按钮 .inner往右移动,是添加一个正的left距离 第52行判断条件的意思是,如果speed小于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果大于他则不停的去加上-speed去变小 与newLeft相同为止 或者speed大于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果小于他则不停的去加上speed去变大 与 newLeft相同为止。
  2. newLeft = parseInt(inner.style.left) + offset; 表示最终目标值,存进了变量newLeft中,下面inner.style.left获取的都是现在的left值
  3. go函数里面用的是setTimeout()来递归,通过判断条件,来递归go函数。开始我用的是setInterval()方法,导致出现了奇异的动画效果,思路错了,应该在if前面添加一个clearInterval()清除方法,因为如果不清除的话会不断的调用go函数,导致go函数永远都不会结束,就导致了画面狂闪现象。 setTimeout()方法是在什么时间以后干什么,干完拉倒。setInterval()不停的去调用函数,直到clearInterval()被调用或者窗口被关闭。
  4. 注意第70行,写完go函数后需要调用他才会执行。

第四步:最终版,添加自动轮播效果

  1     <script>
  2         window.onload=function(){
  3             var pic = document.getElementById("pic");
  4             var inner = document.getElementById("inner");
  5             var li = document.getElementById("ul").getElementsByTagName("a");
  6             var prev = document.getElementById("prev");
  7             var next = document.getElementById("next");
  8             var index = 1;
  9             var timer = null;
 10             //设置一个变量来存放自动轮播定时器
 11             var timer2 = null;
 12             <

以上是关于用原生的javascript 实现一个无限滚动的轮播图的主要内容,如果未能解决你的问题,请参考以下文章

浅谈轮播图(原生JavaScript实现)

原生javascript手写一个丝滑的轮播图

JavaScript:100%原生js实现左右切换的轮播图(无延迟加载)

JavaScript:100%原生js实现左右切换的轮播图(有延迟加载)

原生JavaScript实现滚动条

iOS无限轮播图片的实现-仅仅用了三个UIImageView实现多图的轮播效果