js轮播图改进版

在肝前端大作业时,产生了使用轮播图的想法,翻阅了之前自己发过的一篇帖子,发现完全不能满足现在的需求,发现csdn上一篇帖子的代码写的不错,于是摘录下来学习

实现的效果:

  • 自动播放
  • 鼠标停留时停止播放,显示左右切换
  • 点击左右切换、下方圆形可以手动切换
  • 图片无缝切换,首位切换无违和感

采用胶片播放方式来切换图片

经过css修饰后

html部分

<!DOCTYPE html>
<head>
</head>
<body>
    <div id="box">
        <div id="slider">
            <ul class="slieder-item-container">
                <li>
                    <a href="#"><img src="img/index1.jpg" /></a>
                </li>
                <li>
                    <a href="#"><img src="img/index2.jpg" /></a>
                </li>
                <li>
                    <a href="#"><img src="img/index3.jpg" /></a>
                </li>
            </ul>
            <div class="arrow-container">
                <span class="left-arrow"><</span>
                <span class="right-arrow">></span>
                <!-- 这个是左右箭头,用于切换图片 -->
            </div>
            <div class="indicator-container">
                <span class="indicator active"></span>
                <span class="indicator"></span>
                <span class="indicator"></span>
                <!-- 这个是图片下方的小圆点,定位第几张图 -->
            </div>
        </div>
</body>

css部分

#slider,
#slider ul,
#slider ul li a {
    width: 800px;
    height: 400px;
    margin: 0;
    padding: 0;
}

#slider {
    position: absolute;
    /* position: relative; */
    border: 2px solid black;
    /*padding: 3px;*/
    margin: 10px 0 0 10px;
    /* z-index: 1; */
    overflow: hidden;
    /* 隐藏显示区域外的图片 */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

#slider ul {
    position: absolute;
    list-style-type: none;
    width: 6000px;
    /* 设置图片列表的长度 */
    /*transition-duration: 0.3s;*/
}

#slider li {
    float: left;
}

#slider a {
    /* display: inline-block; */
    display: block;
}

img {
    width: 100%;
    height: 100%;
}

#slider:hover .arrow-container {
    display: block;
}

.arrow-container {
    position: absolute;
    width: 100%;
    height: 50px;
    top: 50%;
    margin-top: -25px;
    display: none;
}
/* 箭头的样式设计 */
.arrow-container span {
    position: absolute;
    width: 50px;
    height: 50px;
    font-size: 40px;
    /*display: inline-block;*/
    text-align: center;
    line-height: 50px;
    background: rgba(0, 0, 0, 0.2);
    color: white;
}

.left-arrow {
    left: 0px;
    cursor: pointer;
}

.right-arrow {
    right: 0px;
    cursor: pointer;
}
/* 小圆点的样式设计 */
.indicator-container {
    position: absolute;
    width: 150px;
    height: 30px;
    line-height: 30px;
    bottom: 0;
    left: 50%;
    margin-left: -75px;
    text-align: center;
}

.indicator {
    display: inline-block;
    width: 15px;
    height: 15px;
    border-radius: 100%;
    background: white;
    cursor: pointer;
}

.indicator.active {
    background: lightskyblue;
}

js部分

var autoplay = true;
var autoplay_Delay = 2000; // ms
var autoplayId;
var intervalId;

var slider;
var slider_item_container;
var slider_items;
var indicator_container;

var slider_item_width;
var curIndex = 0;

window.onload = function() {
    initElement();
    initEvent();
    if (autoplay) {
        startAnimation(slider_item_container);
    }
}
// 初始化元素
function initElement() {
    slider = document.getElementById("slider");
    slider_items = slider.getElementsByTagName("li");
    slider_item_container = slider.getElementsByClassName("slieder-item-container")[0];
    indicator_container = slider.getElementsByClassName("indicator-container")[0];
    
    var firstItem = slider_items[0].cloneNode(true);
    slider_item_container.appendChild(firstItem);
    
    slider_item_width = slider_items[0].offsetWidth;
}
// 初始化相关事件
function initEvent() {
    slider.addEventListener("mouseover", function () {
        clearTimeout(autoplayId);
        autoplay = false;
    });
    slider.addEventListener("mouseout", function () {
        autoplay = true;
        startAnimation(slider_item_container);
    });
    
    var indicators = indicator_container.children;
    for (var i = 0; i < indicators.length; i++) {
        indicators[i].setAttribute("index", i);
        indicators[i].addEventListener("click", function () {
            var index = parseInt(this.getAttribute("index"));
            next(index);
        });
    }
    
    var left_arrow = slider.getElementsByClassName("left-arrow")[0];
    var right_arrow = slider.getElementsByClassName("right-arrow")[0];
    left_arrow.addEventListener("click", function () {
        prev();
    });
    right_arrow.addEventListener("click", function () {
        next();
    });
}

// 动画效果,传入的形参未要移动的元素以及移动的目标值
// 默认每10ms移动10px,手动翻页时,移动事件缩短,每次移动step值增大
function animate(element, target) {
    var step = 10;
    var time = 10;
    var gap = (Math.abs(target - element.offsetLeft) / slider_item_width);
    if (gap > 1) {
        step = step * gap;
        time = time / gap;
    }
    if (element) {
        step = (element.offsetLeft > target) ? -step : step;
        clearInterval(intervalId);
        setCurrentActiveIndicator(curIndex);
        intervalId = setInterval(function () {
            if ((step < 0) && (Math.abs(element.offsetLeft + step) < Math.abs(target))) {
                element.style.left = element.offsetLeft + step + "px";
            } else {
                if (Math.abs(target - element.offsetLeft) > Math.abs(step)) {
                    element.style.left = element.offsetLeft + step + "px";
                } else {
                    clearInterval(intervalId);
                    intervalId = -1;
                    element.style.left = target + "px";
                    if (autoplay) {
                        startAnimation(element);
                    }
                }
            }
        }, time);
    }
}
/*/ 左右翻页,改变轮播图的left值,改变当前显示的图片,再进行翻页动作,使用户感受不到过明显的跳转变化,

*/
function prev() {
    var element = slider_item_container;
    var li = element.children;
    curIndex = curIndex - 1;
    if (curIndex < 0) {
        element.style.left = -((li.length-1)*slider_item_width) + "px";
        curIndex = li.length-2;
    }
    animate(element, -(curIndex*slider_item_width));
}
// 点击小圆点,也就是单词调用next(),但需要将要跳转的下标值传入
function next(nextIndex) {
    var element = slider_item_container;
    var li = element.children;
    if ((nextIndex != null) && (typeof(nextIndex) != "undefined")) {
        curIndex = nextIndex;
    } else {
        curIndex = curIndex + 1;
        if (curIndex > (li.length-1)) {
            element.style.left = 0 + "px";
            curIndex = 1;
        }
    }
    animate(element, -(curIndex*slider_item_width));
}
// 自动播放,每次轮播图移动到目标位置后,持续调用startAnimation(),内部也是调用next()
function startAnimation(element) {
    if (autoplayId) {
        clearTimeout(autoplayId);
    }
    autoplayId = setTimeout(function () {
        next();
    }, autoplay_Delay);
}

function setCurrentActiveIndicator(index) {
    var indicators = indicator_container.children;
    if (index == indicators.length) {
        index = 0;
    }
    for (var i = 0; i < indicators.length; i++) {
        if (i == index) {
            indicators[i].className = "indicator active";
        } else {
            indicators[i].className = "indicator";
        }
        // 判断当前是第几张图并对小圆点加颜色
    }
}

总结以上一些小细节

  • span设置宽高无效,但设置position: absolute;display: inline-block;就有效了
  • 子元素设置了float: left,父元素的text-align就失效了
  • 圆形border-radius: 50%;
  • 文字上下居中:line-height设置和height一样的值
  • 水平文字居中text-align: center;

JS实现无缝切换轮播图(自动+手动)-f清风q的博客