原生JS实现轮播图

原生JS实现轮播图

js实现轮播图,我经历了一下几个步骤:

  1. 把静态界面写出来
  2. 添加切换上一张下一张的箭头(为了省事,直接用的<>…)
  3. 通过调用setTimeOut,让图片动起来,实现轮播的效果
  4. 给每张图片绑定按钮,在鼠标移到相对应的数字时,就会切换到对应的图片
  5. 写博客总结一哈

先上效果图:

静态页面

静态页面的话没什么好说的,其实就是就是加了几张图片,然后修改了一下样式而已。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        * {
            padding: 0px;
            margin: 0px;
        }
        ul {
            list-style-type: none;
        }
        li {
            float: left;      
        }
        a {
            text-decoration: none;
            font-size: 50px;
            color: gray;
            position: absolute;
            top: 50%;
        }
        #prev {
            left: 0px;
        }
        #next {
            right: 0px;
        }
        .container {
            position: relative;
            margin: 10px auto;
            width: 375px;
            height: 525px;
        }
        .list {
            position: relative;
            width: 400px;
            height: 523px;
            border: 1px solid sienna;
            overflow: hidden;
            cursor: pointer;
        }
        .list ul {
            width:5000px;
            position: absolute;
        }
        .list ul li {
            display: inline;
        }
        .count {
            position: absolute;
            bottom: 10px;
            right: 0px;
        }
        .count li {
            float: left;
            text-align: center;
            font: 20px Arial;
            color: white;
            width: 20px;
            height: 20px;
            opacity: 0.7;
            margin-right: 10px;
            background: #f90;
            border-radius: 20px;
            cursor: pointer;
        }
        .count .current {
            opacity: 1;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="list">
            <ul>
                <li><img src="img/乔巴.jpg" alt="乔巴" width="400" height="523"></li>
                <li><img src="img/路飞.jpg" alt="路飞" width="400" height="523"></li>
                <li><img src="img/山治.jpg" alt="山治" width="400" height="523"></li>
                <li><img src="img/索隆.jpg" alt="索隆" width="400" height="523"></li>
                <li><img src="img/娜美.jpg" alt="娜美" width="400" height="523"></li>
                <li><img src="img/罗宾.jpg" alt="罗宾" width="400" height="523"></li>
                <li><img src="img/乔巴.jpg" alt="乔巴" width="400" height="523"></li>
                <li><img src="img/路飞.jpg" alt="路飞" width="400" height="523"></li>
            </ul>
            <ul class="count">
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li>
                <li>6</li>
            </ul>
            <a href="javascript:prev();" id="prev" class="arrow">&lt;</a>
            <a href="javascript:next();" id="next" class="arrow">&gt;</a>
        </div>      
    </div>
<script src="js/carousel.js"></script>
</body>
</html>

需要注意的是,在图片列表中,第一张和最后一张图片重复添加了,这是为了实现图片之间的带动画效果的无缝切换,后面会讲。

添加箭头

我这里为了省事,直接使用的<>,所以看起来可能不是那么的好看…

最初的计划只是让这两个箭头实现图片的切换,所以写起来就很简单了,只需要在点击箭头时,修改图片的位置就可以了,由于图片的位置使用的是绝对布局,所以位置的改变也是相当方便.


function prev() {
    if(imgList.offsetLeft >= 0) {
        return;
    }
    imgList.style.left = imgList.offsetLeft + 400 + 'px';
}

添加动画效果

最初的版本,只是让图片每隔2.5s移动一下,后面由于需要加上与图片关联的按钮,增加了传入的参数,来方便定位到目标图片的位置。

function movToRight(jmpNum) {
    jmpNum = jmpNum ? jmpNum : 1;
    if(imgList.offsetLeft <= -400*7) {

        clearInterval(id);
        imgList.style.left = "-400px";
        id = setInterval(movToRight, 2500);
    }
    //console.log(imgList.offsetLeft);
    for(let i = 0; i < 40*jmpNum; i++) {
        setTimeout(function() {
            imgList.style.left = imgList.offsetLeft - 10 + 'px';
            //console.log(i);
        },i*10/jmpNum);
    }
}

最开始还有一个判断,当到达整个图片列表的尾部时,就会清除定时器,然后切换回第一张图片,重新开始轮播。第一次的轮播在页面初始化的时候就已经开始了。

当到达最后一张图片,如果直接切换回第一张图片,那么是没有动画效果的,所以为了实现这种动画效果,又在最后重复添加了第一张图片,这样就能无缝实现从最后一张到第一张的切换。第一张之前添加的那张图片也是这个原因。

将图片和按钮绑定

这个是为了实现图片的快速切换,当鼠标移到数字之上,就会切换到对应的图片。

其实就是向数字上添加了onmouseover事件,当鼠标移动到数字上的时候,判断当前图片和目标图片的距离,然后根据相对的位置,决定向左移还是向右移。


function bindNumWithImg() {
    for(let i = 0; i < numList.length; i++) {
        numList[i].onmouseover = function() {
            this.className = "current";
            console.log(this);
            var currImg = -imgList.offsetLeft/400 - 1;
            var diffVal = i - currImg;
            if(diffVal >= 0) {
                movToRight(diffVal);
            } else {
                movToLeft(-diffVal);
            }
        }
        numList[i].onmouseleave = function() {
            this.className = "";
        }
    }
}

总结

整个轮播图实现下来,代码并不多,不过80行左右,不过却让我对于js中的setTimeOut和setInterval这两个方法有了更深的理解。对于这两个方法,我原来用的并不多,或者说几乎没有用过,经过查阅一些资料,也借着这两个方法了解到了JS中的事件队列。JS的执行顺序是由浏览器进行控制的,在页面载入时,首先会对script标签下的代码,通常是一些变量和方法的声明,以及一些初始数据的处理。然后JS进程将等待更多代码的执行,进入空闲。进入空闲后,下一段代码会立即执行。下一段代码的位置就是事件处理队列。就比如说一个onclick方法,当点击那个绑定onclick的元素后,会立即把对应的方法加入到事件处理队列中去,但是不会立即执行,而是等到JS进程空闲时,才会执行代码。

setTimeOut也是这样的,只会在你设定的时间之后添加到事件处理队列中去,但并不一定会立即执行。

在使用setTimeOut时需要注意的是,传入的第一个参数,要么是一个方法,要么是一个代码段,注意,这个代码段是要加引号的,虽然在浏览器中不会报错,但是会立即执行。在node中会报错,指出传入参数不正确。

在实现的过程中,有一个问题困扰了我好久,就是实现的动画效果有些问题,在进行图片切换的时候,会有空白,额说不清楚,上图:

problemExample

后面发现,由于某种原因,在当前图片之后的图片会到下一行,当然了,解决这个问题很简单,设置这一行的宽度很宽就行了,这里换行的原因是,由于是浮动元素,在排列时需要判断最右的边界,默认情况下,浮动元素是不能超过边界的,所以他就会自动的换行了。但是那些浮动的元素却可以到前面去,这是因为通过left改变了它的左边界。
最终效果图:
这里写图片描述

下面是完整的JS代码:

var list = document.getElementsByClassName("list")[0];
var imgList = list.getElementsByTagName('ul')[0];
var imgs = imgList.getElementsByTagName("li");
var numList = list.getElementsByClassName("count")[0].getElementsByTagName('li');
var id;//setInterval 的id

function init() {
    imgList.style.left = "-400px";
    list.onmouseover = function() {
        clearInterval(id);
    }
    list.onmouseout = function() {
        id = setInterval(movToRight, 2500);
    }
    autoPlay();
    bindNumWithImg();
}

function bindNumWithImg() {
    for(let i = 0; i < numList.length; i++) {
        numList[i].onmouseover = function() {
            this.className = "current";
            console.log(this);
            var currImg = -imgList.offsetLeft/400 - 1;
            var diffVal = i - currImg;
            if(diffVal >= 0) {
                movToRight(diffVal);
            } else {
                movToLeft(-diffVal);
            }
        }
        numList[i].onmouseleave = function() {
            this.className = "";
        }
    }
}

function next() {
    movToRight();
}

function prev() {
    movToLeft();
}

//使得图片向左播放
function movToLeft(jmpNum) {
    jmpNum = jmpNum ? jmpNum : 1;
    if(imgList.offsetLeft >= 0) {
        imgList.style.left = "-2400px";
    }
    for(let i = 0; i < 40 * jmpNum; i++) {
        setTimeout(function() {
            imgList.style.left = imgList.offsetLeft + 10 + 'px';
        }, i*10/jmpNum);
    }
}

//使得图片向右播放
function movToRight(jmpNum) {
    jmpNum = jmpNum ? jmpNum : 1;
    if(imgList.offsetLeft <= -400*7) {

        clearInterval(id);
        imgList.style.left = "-400px";
        id = setInterval(movToRight, 2500);
    }
    //console.log(imgList.offsetLeft);
    for(let i = 0; i < 40*jmpNum; i++) {
        setTimeout(function() {
            imgList.style.left = imgList.offsetLeft - 10 + 'px';
            //console.log(i);
        },i*10/jmpNum);
    }
}

function autoPlay() {
    id = setInterval(movToRight, 2500);
}

init();

其中的方法的设计可能有些不足,还请多多指点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值