用原生js实现移动端图片轮播

本文详细介绍了一种轮播图无缝切换的实现方法,通过在首尾添加图片、修改页面结构和样式,配合定时器、触摸事件及过渡效果,实现了图片的自动和手动轮播,确保了用户体验的流畅性和视觉效果的连续性。

 

1.实现思路

1.在首尾添加图片
    1.在开始位置添加原始的最后一张图片
    2.在最后位置添加原始的第一张图片


2.修改页面结构
3.修改对应的样式

.jd_bannerImg{
    width:1000%;
}
.jd_bannerImg > li{
    width:10%;
    float: left;
}


4.设置默认的偏移:默认应该显示索引1的图片
    transform:translateX(-10%):参照自身
    left:-100%:参照父容器
    使用定位实现的细节:当前元素必须使用relative定位,否则父容器无法获取正确的高度

5.自动轮播
    定时器
    1.添加过渡效果
    2.修改left样式实现偏移
    3.当移动到最后一张,清除过渡,将图片偏移到索引1的位置--延迟操作


6.实现手动轮播:
    1.记录手指的起始位置
    2.记录手指在滑动过程中的位置,计算出相对于起始位置的偏移值,通过left样式实现图片的偏移
    3.在松开手指之后,判断当前滑动的距离,如果超出指定的范围,就翻页,否则回弹
    4.松开手指之后,重新开启定时器

7.添加过渡结束的监听:webkitTransitionEnd

细节:touch事件的触发,必须保证元素有具体的宽高,如果宽或高为0,则不会进行触发

 

2.代码实现

(1)html和css

  • 图片方面:如果要轮播8张图,那么页面上要写10张图,额外的两张图主要是为了从第一张往前切换和最后一张往后切换的无缝衔接,不会出现最后一张空白情况。
  • 布局方面:分为两层,一层包括图片是,使用 relative 定位,一层包括小圆圈按钮,使用 absolute 定位。

index.css

/*轮播图样式*/
.jd_banner{
    width: 100%;
    overflow: hidden;
    position: relative;
}
/*.jd_bannerImg{
    width:800%;
}*/
.jd_bannerImg{
    width:800%;
    /*position: absolute;  如果使用absolute定位,会造成父容器无法获取由子元素的撑开的高度*/
    position: relative;
    /*添加默认偏移*/
    /*transform: translateX(-10%);*/
    /*使用定位:使用百分比的时候是参照父容器的宽度*/
   /* left: -100%;*/
}
/*.jd_bannerImg > li{
    width:12.5%;
    float: left;
}*/
.jd_bannerImg > li{
    width:12.5%;
    float: left;
}
.jd_bannerImg > li img{
    /*1.设置为块元素
    2.可以将文本的字体大小设置为0
    3.vertical-align:bottom*/
    display: block;
    width: 100%;
}
.jd_bannerIndicator{
    width: 128px;
    height: 10px;
    position: absolute;
    left: 50%;
    bottom: 5px;
    transform: translateX(-50%);
}
.jd_bannerIndicator > li{
    width: 6px;
    height: 6px;
    border-radius: 3px;
    border: 1px solid #fff;
    float: left;
    margin-left:10px;
}
.jd_bannerIndicator > li:first-of-type{
    margin-left:0;
}
.jd_bannerIndicator > li.active{
    background-color: #fff;
}

index.html

<!--轮播图-->
    <div class="jd_banner">
        <!--图片-->
        <ul class="jd_bannerImg clearfix">
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l1.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l2.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l3.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l4.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l5.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l6.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/l7.jpg" alt="">
                </a>
            </li>
            <li>
                <a href="javascript:;">
                    <img src="./uploads/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>

 

(2)js实现

/*轮播图*/
function bannerEffect() {
    /*1.设置修改轮播图的页面结构
     * a.在开始位置添加原始的最后一张图片
     * b.在结束位置添加原始的第一张图片*/
    /*1.1.获取轮播图结构*/
    var banner = document.querySelector(".jd_banner");
    /*1.2.获取图片容器*/
    var imgBox = banner.querySelector("ul:first-of-type");
    /*1.3.获取原始的第一张图片*/
    var first = imgBox.querySelector("li:first-of-type");
    /*1.4.获取原始的最后一张图片*/
    var last = imgBox.querySelector("li:last-of-type");
    /*1.5.在首尾插入两张图片   cloneNode:复制一个dom元素*/
    imgBox.appendChild(first.cloneNode(true));
    /*insertBefore(需要插入的dom元素,位置)*/
    imgBox.insertBefore(last.cloneNode(true), imgBox.firstChild);

    /*2.设置对应的样式*/
    /*2.1获取所有图片li元素*/
    var lis = imgBox.querySelectorAll("li");
    /*2.2 获取li元素的数量*/
    var count = lis.length;
    /*2.3.获取banner的宽度*/
    var bannerWidth = banner.offsetWidth;
    /*2.4 设置图片盒子的宽度*/
    imgBox.style.width = count * bannerWidth + "px";
    /*2.5 设置每一个li(图片)元素的宽度*/
    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 () {
        /*4.1.获取banner的宽度,覆盖全局的宽度值*/
        bannerWidth = banner.offsetWidth;
        /*4.2 设置图片盒子的宽度*/
        imgBox.style.width = count * bannerWidth + "px";
        /*4.3设置每一个li(图片)元素的宽度*/
        for (var i = 0; i < lis.length; i++) {
            lis[i].style.width = bannerWidth + "px";
        }
        /*4.4重新设置定位值*/
        imgBox.style.left = -index * bannerWidth + "px";
    }

    /*实现点标记*/
    var setIndicator = function (index) {
        var indicators = banner.querySelector("ul:last-of-type").querySelectorAll("li");
        /*先清除其它li元素的active样式*/
        for (var i = 0; i < indicators.length; i++) {
            indicators[i].classList.remove("active");
        }
        /*为当前li元素添加active样式*/
        indicators[index - 1].classList.add("active");
    }

    var timerId;
    /*5.实现自动轮播*/
    var startTime = function () {
        timerId = setInterval(function () {
            /*5.1 变换索引*/
            index++;
            /*5.2.添加过渡效果*/
            imgBox.style.transition = "left 0.5s ease-in-out";
            /*5.3 设置偏移*/
            imgBox.style.left = (-index * bannerWidth) + "px";
            /*5.4 判断是否到最后一张,如果是则回到索引1的位置*/
            setTimeout(function () {
                if (index == count - 1) {
                    index = 1;
                    /*如果一个元素的某个属性之前添加过过渡效果,那么过渡属性会一直存在,如果不想要,则需要清除过渡效果*/
                    /*关闭过渡效果*/
                    imgBox.style.transition = "none";
                    /*偏移到指定的位置*/
                    imgBox.style.left = (-index * bannerWidth) + "px";
                    setIndicator(index);
                }
            }, 500);
        }, 1000);
    }
    startTime();

    /*6.实现手动轮播*/
    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";
            /*实现元素的偏移  left参照最原始的坐标
             * 重大细节:本次的滑动操作应该基于之前轮播图已经偏移的距离*/
            imgBox.style.left = (-index * bannerWidth + distanceX) + "px";
        }
    });
    /*添加触摸结束事件*/
    /*touchend:松开手指触发*/
    imgBox.addEventListener("touchend", function (e) {
        /*松开手指,标记当前过渡效果正在执行*/
        isEnd = false;
        /*获取当前滑动的距离,判断距离是否超出指定的范围 100px*/
        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";
        }
        /*将上一次move所产生的数据重置为0*/
        startX = 0;
        moveX = 0;
        distanceX = 0;
    });

    /*webkitTransitionEnd:可以监听当前元素的过渡效果执行完毕,当一个元素的过渡效果执行完毕的时候,会触发这个事件*/
    imgBox.addEventListener("webkitTransitionEnd", function () {
        console.log("webkitTransitionEnd");
        /*如果到了最后一张(count-1),回到索引1*/
        /*如果到了第一张(0),回到索引count-2*/
        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);
        setTimeout(function () {
            isEnd = true;
            /*清除之前添加的定时器*/
            clearInterval(timerId);
            //重新开启定时器
            startTime();
        }, 100);
    });
}

 

结束

如果文章对你有帮助,麻烦点赞哦!一起走码农花路~

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值