js原生—— 无缝轮播

今天分享前端开发学习中的一个很经典的案例——原生JS实现无缝轮播图。

需求:

1.鼠标移入轮播图时左右两边显示上一页下一页按钮,移出时隐藏

2.鼠标点击箭头,图片发生轮播

3.点击号码,切换到指定图片

4.鼠标移出,图片每隔一定时间自动轮播

5.当图片轮播到最后或最前一张的时候,图片无缝循环切换

<div class="all" id='box'>
    <div class="screen">
        <ul>
            <li><img src="" width="500" height="200" style="background-color: yellowgreen;"/></li>
            <li><img src="" width="500" height="200" style="background-color: pink;"/></li>
            <li><img src="" width="500" height="200" style="background-color: skyblue;"/></li>
            <li><img src="" width="500" height="200" style="background-color: greenyellow;"/></li>
            <li><img src="" width="500" height="200" style="background-color: plum;"/></li>
            <li><img src="" width="500" height="200" style="background-color: orange;"/></li>
        </ul>
        <ol>
            <li class="current">1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
        </ol>

    </div>
    <div id="arr"><span id="left"><</span><span id="right">></span></div>
</div>

CSS样式:样式部分比较简单,重点让li标签浮动并排,然后在盒子(类名为screen的div)里显示其中一张,其他的隐藏(overflow:hidden),整个轮播思想就是移动整个ul标签。

<style type="text/css">
        * {
            padding: 0;
            margin: 0;
            list-style: none;
            border: 0;
        }

        .all {
            width: 500px;
            height: 200px;
            padding: 7px;
            border: 1px solid #ccc;
            margin: 100px auto;
            position: relative;
        }

        .screen {
            width: 500px;
            height: 200px;
            overflow: hidden;
            position: relative;
        }

        .screen li {
            width: 500px;
            height: 200px;
            overflow: hidden;
            float: left;
        }

        .screen ul {
            position: absolute;
            left: 0;
            top: 0px;
            width: 3000px;
        }

        .all ol {
            position: absolute;
            right: 10px;
            bottom: 10px;
            line-height: 20px;
            text-align: center;
        }

        .all ol li {
            float: left;
            width: 20px;
            height: 20px;
            background: #fff;
            border: 1px solid #ccc;
            margin-left: 10px;
            cursor: pointer;
        }

        .all ol li.current {
            background: yellow;
        }

        #arr {
            display: none;
        }

        #arr span {
            width: 40px;
            height: 40px;
            position: absolute;
            left: 5px;
            top: 50%;
            margin-top: -20px;
            background: #000;
            cursor: pointer;
            line-height: 40px;
            text-align: center;
            font-weight: bold;
            font-family: '黑体';
            font-size: 30px;
            color: #fff;
            opacity: 0.3;
            border: 1px solid #fff;
        }

        #arr #right {
            right: 5px;
            left: auto;
        }
    </style>

JS处理:

第一步:完成轮播图事件的添加 :用一个全局变量index记录当前需要展示的图片的索引

(1)鼠标移入移出事件:鼠标移入,显示左右切换按钮,移出时隐藏

(2)上一页下一页按钮点击事件点击下一页:index++,点击上一页:index--

(3)页码点击事件:切换指定图片

第二步:完成上一页和下一页

(1)点击移动之前给ul添加边界检测:否则点击下一页会无限往右滚动

(2)修改当前索引(自增/自减),索引表示的是当前ul应该展示第几张图片

(3)移动ul(目标距离 = -index * screen的宽度)

(4)页码保持同步(当前显示的是第几张图片,下方页码对应索引高亮)

第三步:完成无限轮播 核心思想:n+1

(1)常规思路:图片滚动时,当滚动到最后一张时,我们偷偷的快速改变ul的位置到第一张(不要动画,瞬间改变)

ul.style.left = '0px'; //ul回到初始位置

index = 0; //index恢复到0

(2)问题发现:这种方式可以实现无限轮播,但是在下一轮无限的时候第一张会被跳过去

原因:我们手动改变了index为0,而动画又需要index+1,所以会错过index为0的那一张

(3)解决方案:我们在最后一张图片的后面加上第一张图片(第6张)可以让用户看到滚动效果,然后滚动到第六张时,再改变ul回到初始位置

好处:①用户可以看到滚动效果,不影响体验; ②刚好第6张与第一张是同一张图片,快速改变位置不会造成动画的闪现

(4)当图片index为最后一张的的时候,页码应该显示第一个,因为最后一张和第一张是同一张图片

第四步:完成点击页码跳转

(1)点击的是第几个页码,移动动画的目标距离 = -index * screen.offsetWidth

(2)排他思想改变页码样式

(3)页码的下标需要与图片下标index保持一致,否则会产生冲突,即点击页码的时候,要让图片下标index与页码下标一致

第五步:自动无限轮播

相当于每隔一段时间自动点击下一页按钮,代码逻辑完全不变

(1)将轮播代码封装成一个函数

(2)开启定时器,每隔一段时间执行这个函数

(3)鼠标移入时清除定时器,移出时开启定时器

<script>
    // 1.获取页面对应的元素
    var box=document.getElementById("box"); //最外部大盒子
    var arr=document.getElementById("arr");
    var screen=document.getElementsByClassName("screen")[0]; //轮播图显示区域div
    var ul=document.getElementsByTagName("ul")[0]; //显示图片的ul
    var ol=document.getElementsByTagName("ol")[0]; //显示页码的ol
    var left=document.getElementById("left"); //上一张箭头
    var right=document.getElementById("right"); //下一张箭头
    var index=0; ////声明一个变量记录图片的索引,默认第0张图片

    //2.给box添加鼠标移入和移出事件
    //2.1 鼠标移入
    box.onmouseover= function () {
        arr.style.display="block"; //显示上一页下一页箭头
        clearInterval(timeId); //清除定时器(即鼠标移入时,图片要停止自动轮播)
    };
    //2.2 鼠标移出
    box.onmouseout= function () {
        arr.style.display="none"; //隐藏箭头
        timeId=setInterval(scroll,2000);  //重启定时器(鼠标移出,图片要恢复自动轮播)
    };

    //3.给上一页下一页箭头添加点击事件
    //3.1 下一页,图片向左轮播
    right.onclick= function () {
        scroll();
    };
    //3.2 上一页,图片向右轮播
    left.onclick= function () {
        //(1)边界检测,如果当前已经是第一张,则不做任何处理
        if(index==0){
            //无限轮播原理:如果当前是第一张,则偷偷修改ul的位置是最后一张(第一张与最后一张是同一张图片)
            index=ul.children.length-1; //index恢复到最后一张
            ul.style.left=-index*screen.offsetWidth+"px"; ////ul回到最后一张位置
        }
        //(2)索引自减
        index--;
         // (3)向左移动ul:目标距离 = -screen的宽度 * 索引
        animationMove(ul,-index*screen.offsetWidth,10);
        indexShow(); //同步页码样式
    };

    //4.给页码添加点击事件
    for(var i=0;i<ol.children.length;i++){
         //4.1 循环遍历数组时给每一个页码添加一个liIndex属性记录下标
        ol.children[i].liIndex=i;
        ol.children[i].onclick= function () {
            index=this.liIndex-1;
            scroll();
        };
    }

    var timeId=setInterval(scroll,2000);
    // 封装一个向右轮播的函数
    function scroll(){
        //(1)边界检测:如果当前已经是最后一张(第n+1张,n代表需要轮播的图片数量)
        if(index==ul.children.length-1){
            //无限轮播的原理就是滚动到最后一张的时候,偷偷快速的改变ul的位置到第一张(不要任何动画,一瞬间改变)
            index=0; //index恢复到0
            ul.style.left=0+"px"; //ul回到初始位置
        }
        // (2)索引自增
        index++;
        // (3)向右移动ul:目标距离 = -screen的宽度 * 索引
        animationMove(ul,-index*screen.offsetWidth,10);
        indexShow(); //同步页码样式
    }
    //5.页码样式保持同步:排他思想(当前页码添加样式,其他页码移除该样式)
    function indexShow(){
        for(var i=0;i<ol.children.length;i++){
            if(i==index){
                ol.children[i].classList.add("current");
            }else{
                ol.children[i].classList.remove("current");
            }
            //特殊情况:当index为最后一张的时候,页码应该显示第一张
            if(index==ul.children.length-1){
                ol.children[0].classList.add("current");
            }
        }
    }
    // 封装一个滚动动画函数
    function animationMove(obj,target,speed){
        clearInterval(obj.timeId);  //每次执行动画先清除原有的定时器
        obj.timeId=setInterval(function () {
            var currentLeft=obj.offsetLeft; //获取当前位置
           var isLeft=currentLeft>target?true:false;   //是否往左走
           if(isLeft){
               currentLeft-=10;    //往左走
           }else{
               currentLeft+=10;    //往右走
           }
           if(isLeft?currentLeft>target:currentLeft<target){
              obj.style.left=currentLeft+"px";  //如果当前位置不是在目标位置则进行位置处理
           }else{
               clearInterval(obj.timeId);
               obj.style.left=target+"px";
           }
        },speed);
    }
</script>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容