zoukankan      html  css  js  c++  java
  • 用原生的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             var state = false;
     13             prev.onclick = function(){
     14                 if(state){
     15                     return;
     16                 }
     17                 animate(600);
     18                 if(index==1){
     19                     index=5;
     20                 }else{
     21                     index--;
     22                 }
     23                 showButton();
     24             }
     25             next.onclick = function(){
     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                 state = true;
     40                 var time = 300;
     41                 var interval = 10;
     42                 var speed = offset/(time/interval);
     43 
     44                 var newLeft = parseInt(inner.style.left) + offset;
     45                 function go(){
     46                     clearInterval(timer);
     47                     if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){
     48                         inner.style.left = parseInt(inner.style.left) + speed + "px";
     49                         timer=setInterval(go,interval);
     50                     }else{
     51                         state = false;
     52                         inner.style.left = newLeft + "px";
     53                         if(parseInt(inner.style.left) < -3000){
     54                         inner.style.left = -600 + "px";
     55                         }
     56                         if(parseInt(inner.style.left) > -600){
     57                         inner.style.left = -3000 + "px";
     58                         }
     59                     }
     60                 }
     61                 go();
     62                 
     63             }
     64             function showButton(){
     65                 for(var i=0;i<li.length;i++){
     66                     if(li[i].className=="active"){
     67                         li[i].className="";
     68                         break;
     69                     }
     70                 }
     71                 li[index-1].className="active";
     72             }
     73             for(var i=0;i<li.length;i++){
     74                 li[i].onclick=function(){
     75                     var id = parseInt(this.getAttribute("id"));
     76                     var offset = (id-index) * -600;
     77                     if(state){
     78                     return;
     79                     }    
     80                     animate(offset);
     81                     index = id;
     82                     showButton();
     83                 }
     84             }
     85             //通过定时器来不断的点击 next按钮 来实现轮播效果.
     86             function play(){
     87                 timer2 = setInterval(function(){
     88                     next.onclick();
     89                 },3000);
     90             }
     91             //停止轮播函数,清除定时器
     92             function stop(){
     93                 clearInterval(timer2);
     94             }
     95             //给.pic添加移进悬浮和移出事件
     96             pic.onmouseover = stop;
     97             pic.onmouseout = play;
     98             //第一次访问页面开始轮播
     99             play();    
    100         }
    101     </script>

    需要注意的地方:

    1. 触发next的点击事件,可以写成next.onclick()来触发
    2. 给.pic添加事件 不能写成pic.onmouseover = stop(),加了括号后代表立即调用函数,而不是我们需要的悬浮在pic盒子上时调用.

    总结:第一次学习这个轮播图时,因为思路跟不上,导致看不懂,然后我又从简单的做起,比如我先学习做了一个自动轮播标签页(前面博客有总结),然后又学习用jq写了一个简单的轮播图,再过来学习这个难度大的,循序渐进去学习,就会发现自己能懂甚至写出来这个轮播图了,附上我学习的视频链接地址。

    标签切换地址:http://www.imooc.com/learn/176

    JQ轮播图地址:http://www.cnblogs.com/yewenxiang/p/6100206.html

    原生js轮播图地址:http://www.imooc.com/learn/176

    这篇博客是我目前写的最长的一篇,时间跨度两天,中间多有疏漏或者不正确的地方还希望能指出,我改正。

  • 相关阅读:
    Codeforces Beta Round #9 (Div. 2 Only) C. Hexadecimal's Numbers dfs
    Codeforces Beta Round #9 (Div. 2 Only) B. Running Student 水题
    Codeforces Beta Round #9 (Div. 2 Only) A. Die Roll 水题
    51nod 1035 最长的循环节 数学
    BSGS 模板
    51nod 1040 最大公约数之和 欧拉函数
    51NOD 1179 最大的最大公约数 筛法
    BZOJ 2818: Gcd 筛法
    川大校赛总结
    SCOJ 4484 The Graver Robbers' Chronicles 后缀自动机
  • 原文地址:https://www.cnblogs.com/yewenxiang/p/6115931.html
Copyright © 2011-2022 走看看