轮播图制作思路 (全)

原生

1. index.html

  • 图片 ul>li
  • 点标记 ul>li
<div class="jd_layout">
    
    <div class="jd_banner">
        
        <ul class="jd_bannerImg clearfix">
            <li>
                <a href="javascript:;">
                    <img src="images/l1.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l2.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l3.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l4.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l5.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l6.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l7.jpg" alt="">
                a>
            li>
            <li>
                <a href="javascript:;">
                    <img src="images/l8.jpg" alt="">
                a>
            li>
        ul>
        
        <ul class="jd_bannerIndicator">
            <li class="active">li>
            <li>li>
            <li>li>
            <li>li>
            <li>li>
            <li>li>
            <li>li>
            <li>li>
        ul>
    div>
div>

2.步骤

2.1 修改轮播图的页面结构

  • 克隆第一张和最后一张图,实现无缝转接
    imgBox.appendChild(first.cloneNode(true));
    imgBox.insertBefore(last.cloneNode(true),imgBox.firstChild);

2.2 设置对应的样式

  • 获取轮播图显示区域的宽度 bannerWidth
  • 遍历每一个li,设置宽为bannerWidth
  • 设置所有li排列在一行的宽imgBox = bannerWidth * li的个数 + ‘px’
    var lis=imgBox.querySelectorAll("li");
    var count=lis.length;
    var bannerWidth=banner.offsetWidth;
    imgBox.style.width=count*bannerWidth+"px";
    for(var i=0;i<lis.length;i++){
        lis[i].style.width=bannerWidth+"px";
    }

2.3 设置默认偏移

  • 因为之前将最后一张克隆到了最前面,所以需要设置偏移
  • imgBox.style.left=-bannerWidth+"px";

2.4 屏幕变化更改宽度

  • 使用window.onresize监听
  • 重复之前设置样式的步骤
    • 注意bannerWidth不需要再声明var
  • 再次设置默认偏移
/*4.当屏幕变化的时候,重新计算宽度*/
window.onresize=function(){
  bannerWidth=banner.offsetWidth;
  imgBox.style.width=count*bannerWidth+"px";
  for(var i=0;i<lis.length;i++){
     lis[i].style.width=bannerWidth+"px";
   }
   imgBox.style.left=-index*bannerWidth+"px";
}

2.5 实现点标记

  • 要达到同步效果需让图片的索引和点的索引一致
  • 调用封装好的方法传入当前图片的索引
    • 初始图片索引为1,点的初始索引为0
    • 让图片和点的索引对应,需将图片的索引减去1
  • 获取所有点标记的li移除active样式
  • 当前li设置active样式
    /*5.实现点标记*/
   var index = 1
   var setIndicator=function(index){
       var indicators=banner.querySelector("ul:last-of-type").querySelectorAll("li");
       for(var i=0;i<indicators.length;i++){
           indicators[i].classList.remove("active");
       }
       indicators[index-1].classList.add("active");
   };

2.6 实现自动轮播

  • 使用定时器
  • index++
  • 设置新的偏移(-index*bannerWidth)+"px"
  • 如果图片轮播到最后一张,后续继续轮播会没有图片,所以应该重新跳转到第二张
    /*6.实现自动轮播*/
    var startTime=function(){
        timerId=setInterval(function(){
            index++;
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=(-index*bannerWidth)+"px";
            setTimeout(function(){
                if(index==count-1){
                 //轮播到最后一张
                    index=1;
                    imgBox.style.transition="none";
                    imgBox.style.left=(-index*bannerWidth)+"px";
                }
            },500);

        },1000);

    }
    startTime();

2.7 实现手动轮播

touchstart

  • 清除轮播的定时器
    imgBox.addEventListener("touchstart",function(e){
        clearInterval(timerId);
        startX= e.targetTouches[0].clientX;
    });

touchmove

  • 计算两点之间X轴距离distanceX
  • 设置新偏移 = 原偏移+ distanceX
  • 开启定时器的时候添加了过渡效果,在touchmove的时候没有清除这个过渡也就导致那个延迟了,解决的办法是在touchmove事件中清除过渡
    imgBox.addEventListener("touchmove",function(e){
        if(isEnd==true){
            console.log("touchmove");
            moveX= e.targetTouches[0].clientX;
          	//计算距离
            distanceX=moveX-startX;
          	//清除过渡
            imgBox.style.transition="none";
            //设置偏移
            imgBox.style.left=(-index*bannerWidth + distanceX)+"px";
        }
    });

touchend

  • 若移动距离小于给定的值则状态不变

  • 否则判断左移还是右移,修改相应的index并设置相应的偏移

  • 起始位置和移动距离归零

    imgBox.addEventListener("touchend",function(e){
        isEnd=false;
        if(Math.abs(distanceX) > 100){
            if(distanceX > 0){//上一张
                index--;
            }
            else{ //下一张
                index++;
            }
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        else if(Math.abs(distanceX) > 0){
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=-index*bannerWidth+"px";
        }
     //初始化
        startX=0;
        moveX=0;
        distanceX=0;
    });

webkitTransitionEnd

  • webkitTransitionEnd:当过渡效果执行完成以后执行这个事件
  • 当从一张图片滑动到结束的图片,再继续滑动会出现空白
    imgBox.addEventListener("webkitTransitionEnd",function(){
      //最后一张时
        if(index==count-1){
            index=1;
            imgBox.style.transition="none";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        else if(index==0){
        //第一张时
            index=count-2;
            imgBox.style.transition="none";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        setIndicator(index);
        isEnd=true;
    });

3. 出现过的bug

3.1 快速滑动会出现空白的

  • 原因:当前滑动距离超过100,图片完成过渡效果需0.5s,这时用户又接着多次滑动就导致此时的transitionEnd没有触发,从而就导致了空白问题
  • 解决:使用节流阀进行拦截(如果当前有人在办理业务,就把这个拉上,等办完了再打开)
  • 步骤
    • 初始一个全局变量 设置其值为true
    • 在touchmove事件判断阀门是否开启

3.2 无法滑到下一张

  • 原因:touchmove和transitionEnd都没有触发轮播图却还可以滑动轮播 就是touchend在触发,因为上一次的touchmove虽然没在被触发,但touchmove中的distance值却存在导致后面滑动的distance是一个固定值。
  • 解决:对每次触摸后的值进行初始化为0

4. JS代码

window.onload=function(){
    bannerEffect();
}
function  bannerEffect(){
    /*1.设置修改轮播图的页面结构*/
    var banner=document.querySelector(".jd_banner");
    var imgBox=banner.querySelector("ul:first-of-type");
    var first=imgBox.querySelector("li:first-of-type");
    var last=imgBox.querySelector("li:last-of-type");
    imgBox.appendChild(first.cloneNode(true));
    imgBox.insertBefore(last.cloneNode(true),imgBox.firstChild);

    /*2.设置对应的样式*/
    var lis=imgBox.querySelectorAll("li");
    var count=lis.length;
    var bannerWidth=banner.offsetWidth;
    imgBox.style.width=count*bannerWidth+"px";
    for(var i=0;i<lis.length;i++){
        lis[i].style.width=bannerWidth+"px";
    }
    var index=1;

    /*3.设置默认的偏移*/
    imgBox.style.left=-bannerWidth+"px";

    /*4.当屏幕变化的时候,重新计算宽度*/
    window.onresize=function(){
        bannerWidth=banner.offsetWidth;
        imgBox.style.width=count*bannerWidth+"px";
        for(var i=0;i<lis.length;i++){
            lis[i].style.width=bannerWidth+"px";
        }
        imgBox.style.left=-index*bannerWidth+"px";
    }

    /*5.实现点标记*/
   var setIndicator=function(index){
       var indicators=banner.querySelector("ul:last-of-type").querySelectorAll("li");
       for(var i=0;i<indicators.length;i++){
           indicators[i].classList.remove("active");
       }
       indicators[index-1].classList.add("active");

   };

    var timerId;
    /*6.实现自动轮播*/
    var startTime=function(){
        timerId=setInterval(function(){
            index++;
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=(-index*bannerWidth)+"px";
            setTimeout(function(){
                if(index==count-1){
                    index=1;
                    imgBox.style.transition="none";
                    imgBox.style.left=(-index*bannerWidth)+"px";
                }
            },500);

        },1000);

    }
    startTime();


    /*7.实现手动轮播*/
    var startX,moveX,distanceX;
    var isEnd=true;
    imgBox.addEventListener("touchstart",function(e){
        clearInterval(timerId);
        startX= e.targetTouches[0].clientX;
    });
    imgBox.addEventListener("touchmove",function(e){
        if(isEnd==true){
            console.log("touchmove");
            moveX= e.targetTouches[0].clientX;
            distanceX=moveX-startX;
            imgBox.style.transition="none";
            imgBox.style.left=(-index*bannerWidth + distanceX)+"px";
        }
    });
    imgBox.addEventListener("touchend",function(e){
        isEnd=false;
        if(Math.abs(distanceX) > 100){
            if(distanceX > 0){//上一张
                index--;
            }
            else{ //下一张
                index++;
            }
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        else if(Math.abs(distanceX) > 0){
            imgBox.style.transition="left 0.5s ease-in-out";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        startX=0;
        moveX=0;
        distanceX=0;
    });

    imgBox.addEventListener("webkitTransitionEnd",function(){
        if(index==count-1){
            index=1;
            imgBox.style.transition="none";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        else if(index==0){
            index=count-2;
            imgBox.style.transition="none";
            imgBox.style.left=-index*bannerWidth+"px";
        }
        setIndicator(index);
        isEnd=true;
    });
}

zepto实现轮播图

1. 步骤

  • 添加首尾两张图片
  • 重新设置盒子的宽度和图片的宽度
  • 开启定时器,实现自动轮播
  • 添加移动端的滑动事件,实现手动轮播
  • 添加过渡效果结束之后的监听

2. 代码

$(function(){
        // 获取轮播图元素
        var banner = $('.jd_banner');
        var bannerWidth = banner.width();
        //获取图片盒子
        var imgBox = banner.find('ul:first-of-type');
        //获取点标记
        var indicators = banner.find("ul:eq(1)").find("li");
        //获取首尾两张图片
        var first = imgBox.find('li:first-of-type');
        var last = imgBox.find('li:last-of-type');
        //将两张图片添加到首层位置 first.clone():将first拷贝一份
        imgBox.append(first.clone());
        last.clone().insertBefore(first);

        //设置图片盒子的宽度
        var lis = imgBox.find('li');
        var count = lis.length;
        imgBox.width(count * bannerWidth);
        //设置li标签的宽度
        lis.each(function(index,value){
            $(lis[index]).width(bannerWidth)
        });
        //设置默认偏移
        imgBox.css('left',-bannerWidth);
        //定义图片索引
        var index = 1;
        //开启定时器
        setInterval(function(){
            index++;
            imgBox.animate({"left":-index * bannerWidth},200,'ease-in-out',function(){
                if(index == count - 1){//最后一张
                    index = 1;
                    //让它瞬间偏移到索引1的位置 -- 非过渡
                    imgBox.css('left',-index * bannerWidth);
                }else if(index == 0){
                    index = count - 2;
                    imgBox.css('left',-index * bannerWidth);
                }
                //设置点标记
                indicators.removeClass('active').eq(index-1).addClass('active');
            })
        },2000)
        
        //添加滑动事件
+        imgBox.on('swipeLeft',function(){
+            console.log('swipeLeft');
+        })
+        imgBox.on('swipeRight',function(){
+            console.log('swipeRight');
+        })
+    })

Swiper

  • Swiper4.x使用方法
  • Swiper Animate使用方法
  • Vue中使用Swiper

MUI

  • gallery

NUTUI

  • 有滑动懒加载图片功能

Mint-UI

  • swipe

你可能感兴趣的:(JS)