原生js实现轮播图的两种方法

一.原生js实现幻灯片效果(直接跳转法)

1.分析需求:

幻灯片的效果就是在一个可视区域里面,若干个图片进行交替出现,像在下面的图中,可视区域中的图是轮流出现的。

 

那么如何来实现这个效果呢,我百度了一下大部分都是什么调节left的大小,我没看懂,于是自己来动手来思考怎么做。

首先,刚开始的时候,这个区域就只放一张图,等到需要切换的时候就把这个img的src属性修改为需要展示图片所在的位置。

 

那么如何来实现这个功能呢?

首先来定义一个全局数组用来存放所有的图片的位置,还有一个全局变量num用来记载这次应该轮到第几个图片位置出现在该区域

var num = 0;

var arrUrl = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg"];

接下来写切换函数,切换函数的主要功能就是将img的src属性改到当前需要的位置。

function changeImg(){

    img.src = arrUrl[num];//修改图片的src位置

    //如果图片下方有需要显示的圆点就在这里修改,或者其他对应的信息也在这里修改

    for(var i = 0;i<arrUrl.length;i++){

        li[i].className = "";

        }

    li[num] = "active";



}

接下来分析需要切换的事件

首先是轮播切换,就是一个定时器,定时的调用这个切换函数,并且这里需要注意num的值,因为num切换到最后一张,下一张就应该是第一张。

接下来是点击左右切换按钮,左切换按钮要留意切换到第一张的时候,需要将下一张定义为最后一张,右切换按钮需要留意最后一张,下一张是第一张。

最后是小圆点点击跳转到对应的图片。

 

  • 按照上面的思路,首先来写轮播切换,轮播切换无非就是一个定时器,定时的切换这个图片,所以我们来写一个定时切换的函数

定义一个全局变量定时器(当需要停止定时切换的时候就清除,需要继续的时候就继续调用)

var timer = null;//定义一个空对象来存放定时器

function autoPlay(){

    timer = setInterval(function(){

        num++;//切换下一张的num

        num %=arrUrl.length;//这里是关键,循环播放图片的关键

        },2000);//定时器

}

这里就是定时器的方法实现了,是不是很简单。

只要在全局函数中调用就可以了

 

setTimeout(autoPlay,1000);//延时播放,这样就不用一刷新页面立马切换图片。

 

  • 接下来就是左右切换图片的实现了。左边切换的时候num--,但是要注意num=0的时候,下一场num=arr.Url.length,右切换则相反。

left.onclik = function(){

    num--;

    if(num == -1){

        num = arrUrl.length-1;

    }

    changeImg();//调用切换函数

}



right.onclik = function(){

    num++;

    if(num == arrUrl.length){

        num =0;

    }

    changeImg();//调用切换函数

}

 

 

  • 当图片下面的小圆点点击跳到对应的图片。这里需要为每个原点的index属性添加一个值,就是它对应的i的值,这样每次点击小圆点,直接将img.src = arrUrl[this.index]就可以了。

for(i = 0;i<arrUrl.length;i++){

    li[i].index = i;

        li[i].onclick = function(){

          num = this.index;

            changeImg();

        }

}

 

到了这里,基本都完成了,再添加一个鼠标移入清除定时器,鼠标移出继续调用就可以了

content.onmouseover = function(){

        clearInterval(timer);

    }

contentonmouseout= aotoPlay;

下面是全部的代码

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>原生js实现幻灯片</title>

</head>

<style>

    .container{

        width: 100%;

        height: 500px;

        position: relative;

    }

    .content{

        width: 900px;

        height: 450px;

        position: relative;

        overflow: hidden;

        border: 1px solid seagreen;

        margin: 0 auto;

    }

    .slider-img{

        width: 900px;

        height: 450px;

        margin: 10px auto;

    }

    .slider-img img{

        vertical-align: top;

        width: 800px;

        height: 400px;

        margin: 10px 50px;

        display: block;

    }

    .left{

        margin-top: -300px;

        margin-left: 50px;

        width: 100px;

        height: 100px;



    }

    .left img,.right img{

        width: 100px;

        height: 100px;

    }

    .right{

        margin-top: -100px;

        margin-right: 50px;

        float: right;

        width: 100px;

        height: 100px;

    }



    .dot{

        position: relative;

        top: 23%;

        left: 43%;

        width: 50%;

    }

    .dotul{

        width: 450px;



    }

    .dotul li{

        width: 20px;

        height: 20px;

        background-color: seagreen;

        list-style: none;

        float: left;

        border-radius: 20px;

        margin-left: 15px;

        z-index: 999;

        cursor: pointer;

    }

    .active{

        background-color: orangered !important;

    }



</style>

<body>

    <div class="container" id="contaner">

        <div class="content" id="content">

            <div class="slider-img" id="slider" >

                <a href="javascript:;">

                    <img src="../img/1.jpg" alt="1.jpg" id="img">

                </a>

            </div>

        </div>

        <div class="btn">

            <div class="left" id="left">

                <a href=" ###"><img src="../img/left.png"></a>

            </div>

            <div class="right" id="right">

                <a href=" ###"><img src="../img/right.png"></a>

            </div>

        </div>

        <div class="dot">

            <ul id="ul" class="dotul">

                <li class="active"></li>

                <li></li>

                <li></li>

                <li></li>

                <li></li>

            </ul>

        </div>



    </div>

<script>

    //首先要获取元素

    var container = document.getElementById("container");

    var content = document.getElementById("content");

    var slider = document.getElementById("slider");

    var img = document.getElementById("img");

    var ul = document.getElementById("ul");

    var li = document.getElementsByTagName("li");

    var left = document.getElementById("left");

    var right = document.getElementById("right");

    var num = 0;

    var timer = null;





    //图片位置

    var arrUrl = ["../img/1.jpg","../img/2.jpg","../img/3.jpg","../img/4.jpg","../img/5.jpg"];

    left.onclick = function (ev) {

        num--;

        if (num == -1){

            num = arrUrl.length-1;//如果到了第一张,返回最后一张

        }

        changeImg();

    };

    right.onclick = function (ev) {

        num++;

        if (num == arrUrl.length){

            num = 0;//如果是最后一张,则返回第一张

        }

        changeImg();

    };

    //点击小圆点跳转到对应的图片

    for (var i=0;i<arrUrl.length;i++){

           li[i].index = i;

           li[i].onclick = function (ev) {

               num = this.index;

               changeImg();

           }

    }



    setTimeout(autoPlay(),1000);//延迟1秒执行自动切换



    //鼠标移入清除定时器,鼠标移出恢复

    content.onmouseover = function (ev) {

        clearInterval(timer);

    };

    content.onmouseout = autoPlay;



    //图片切换函数

    function changeImg() {

        img.src = arrUrl[num];//改变图片src位置

        for (var i = 0;i< li.length;i++){//改变原点样式

            li[i].className = "";

        }

        li[num].className = "active";

    }

    //设置定时器

    function autoPlay() {

        timer = setInterval(function () {

            num++;

            num %= arrUrl.length;

            changeImg();

        },2000);

    }

</script>

</body>

</html>

 

 

 

 

二.原生js实现幻灯片效果(左右切换法)

因为第一种方法中,虽然可以实现了幻灯片,但是就是视觉效果不太好。因为突然的跳转,没有一个过渡的缓冲。所以我们再来做一个左右切换幻灯片的效果。

 

我们可以这样想,我们有一副很长的画,但是只有一个窗口,所以每次要看完这幅画都只能在这个窗口往左拉或者往右边拉这幅画,那么这样就实现了轮播的效果了。

 

那么怎么来实现呢?

首先我们要将容器都设上position(因为我们拉这幅画的时候,是通过容器的left来拉动的,而改变这个left使得其起效果,就必须设定position(不能设定为static));

 

我们将最外层的容器设定为position:relative,因为这两层容器只是起到定位的效果,所以我们将其position设定为relative,让他们待在它们原本应该待的地方。

 

然后将放这幅画的容器(放置所有图片最内层的容器)position设定为absolute使其脱离文档流。为什么要这样做呢?

我的思考结果是:有两个原因:(1)因为必须设定Position,所以这里的取值就是relative,和absolute了,至于为什么,请参考笔记Position的研究.(2)选择absolute是因为它脱离了文档流,所以当一张图片需要切换到下一张图片的时候,原来图片的位置不会被占用,而是给了下一张图片的位置了。而子元素又继承了父元素的Position。所以当ul设定了position:absolute的时候,li的position也是absolute,这样就是切换元素的基础。

 

 

其他的样式就不详细说明了,只要保证设定了Position了就可以了。其他按照需要的样式设定就可以了

 

接下来,思考js部分需要怎么写。

首先在js中需要先设定ul的width是所有图片的width的总和。因为这样设定后,后面用js来改变left、width就会起作用。

 

当按下下一张的按钮的时候会发生什么呢?我们来思考一下。

既然按下下一张的时候需要切换到下一张图片,那么此时,我们就要往左边拉这幅长图,怎么拉?把left的值设定为负的一张图的宽度,例如一张图的宽度为500px,那么此时left就等于-500px,此处需要注意的是,这个符号一定要是字符串形式的!!!要用双引号括起来。

 

这个时候我们又会想到,如果这样一直拉,当拉到最后的时候,就是没有元素了吗?此时如果我们再拉,就没有任何元素了怎么办?

 

这是就想到了像数据结构中的循环链表一样了,我们拉这幅画,它是循环的,就是永远没有结尾的,就解决了这个问题。

 

那么怎么实现呢?

我们可以每次拉完这幅图画,就把刚刚拉的那个图画插到长图的最后,此时使用appengChild()函数实现,

(这个函数除了在原来的父元素上添加子元素之外还有一个功能就是,将原来的子元素删除,重新插入到父元素中。)

 

 

 

如果需要呈现慢慢拉到下一张的效果,就一点点的设置left的值,可以设置一个定时器,每次只拉一点点,直到拉完了这幅图,就清除这个定时器。

next.onclick = function (ev) {

  liwidth = 0;

  nextTimer = setInterval(nextImg,animationSpeed);

};

function nextImg() {

    imgul.style.left = "-"+liwidth+"px";

    liwidth += minSpeed;

    if (liwidth >= imgli[0].offsetWidth){

        clearInterval(nextTimer);

        imgul.appendChild(imgli[0]);//先删除imgli[0],然后加到末尾来,这样实现了循环

        imgul.style.left = 0;

    }

}

 

这样,核心功能就完成了。

下面来想,如果是切换上一页的呢?

我们来想,如果按下切换上一页,会发生些什么?

就是left不断的减少,操作跟按右边的刚好相反,按下一张的时候是从0到-width,那么按上一页就是从-width到0。

按照这样的想法,写按上一页的逻辑

prev.onclick = function (ev) {

    imgul.insertBefore(imgli[length-1],imgli[0]);//因为当前图片的位置一直都是imgli[0],所以按照循环的思想,上一张就是imli[length-1]

    clearInterval(prevTimer);

    liwidth = imgli[0].offsetWidth;

    prevTimer = setInterval(prevImg,animationSpeed);

};

function prevImg() {

    imgul.style.left = "-"+liwidth+"px";

    liwidth -= minSpeed;

    if (liwidth <=-1){

        clearInterval(prevTimer);

        imgul.style.left = 0;

    }

}

 

写完切换的逻辑,接下来就写轮播的逻辑

轮播的逻辑就是一个定时器,定时的执行切换下一页的操作。

mainTimer = setInterval(next.onclick,5000);

 

那么到了这里,轮播图的基本逻辑基本上都实现了。

 

但是到了这里我发现了一个bug,就是定时器到了要触发切换的时候,如果我们点击下一页的话,此时会出现一点延迟,(不知道怎么表达,反正就是用户体验不好)。

 

我思考了一下,发现,这个问题的出现,就是当切换到一半的时候,点击了切换下一页,此时,定时器被清除,重新定义定时器。所以就会出现延迟的效果。

 

所以我们定义一个变量,用来记载是否在渲染,如果在渲染,就不再渲染,但是如果没有被渲染,就再一次渲染。

next.onclick = function (ev) {

if (type){

     liwidth = 0;

     clearInterval(nextTimer);//先把上一次留下来的定时器清除(确保清除干净—)

     nextTimer = setInterval(nextImg,animationSpeed);

     type = false;

}

};

function nextImg() {

    imgul.style.left = "-"+liwidth+"px";

    liwidth += minSpeed;

    if (liwidth >= imgli[0].offsetWidth){

        clearInterval(nextTimer);

        imgul.appendChild(imgli[0]);//先删除imgli[0],然后加到末尾来,这样实现了循环

        imgul.style.left = 0;

        type = true;

    }

}

prev.onclick = function (ev) {

    if (type){//如果可以渲染

        imgul.insertBefore(imgli[length-1],imgli[0]);//因为当前图片的位置一直都是imgli[0],所以按照循环的思想,上一张就是imli[length-1]

        clearInterval(prevTimer);

        liwidth = imgli[0].offsetWidth;

        prevTimer = setInterval(prevImg,animationSpeed);

        type = false;//因为设置了定时器,定时器在渲染,所以这时不能被渲染

    }

    };



function prevImg() {

    imgul.style.left = "-"+liwidth+"px";

    liwidth -= minSpeed;

    if (liwidth <=-1){

        clearInterval(prevTimer);

        imgul.style.left = 0;

        type = true;//定时器已经完成渲染了,所以此时可以渲染

    }

}

mainTimer = setInterval(next.onclick,5000);

 

这里基本功能就真的完成啦,现在还差一个小圆点的效果。就是切换到哪一页的时候,哪一页对应的小圆点的背景颜色发生改变。还有当点击哪个小圆点的时候,切换到哪一个小圆点。

 

我们先来思考一下,怎么改变小圆点的背景颜色,因为当前图片的位置一直都是imgli[0],所以我们每次把li[0]的背景颜色改变就好。

那么怎么执行呢?因为如果每次都直接改变dotli[0]的值,那么被改变颜色的一直都只是第一个小圆点。

 

所以我们为没给li加上一个index属性,图片的li和小圆点的li都要加上,这个index的值等于还没有进行切换时的初始值,所以虽然每次当前图片的值都是imgli[0],但是它们对应的index的值是不一样的。所以我们通过这个值进行改变。

 

但是我们发现,如果直接设置的是index是当前,由于定时器完成渲染需要一定的时间,所以小圆点改变背景颜色的时间会有点突兀。所以我们在设置完定时器之后,就改变下一个li的值了,因为此时li仍然是当前值。

 

 

 

接下来来思考当点击小圆点的时候,如何跳转到对应的图片。

当我们点击一个小圆点的时候,先判断这个小圆点应该在当前照片的前面还是后面,如果是在当前图片的前面就往前翻,往前翻(就是从队尾到需要切换到的图片,不断的切换到第一位。)。如果是在当前图片的后面,就往后翻(从当前图片到需要切换到的图片之前的图片全部插到队伍的后面。)

 


 

//为每个小圆点添加点击事件

dot.onclick = function(ev){

    var ev = ev || window.event;

    var target = ev.target || ev.srcElement;

    if(target.nodeName.toLowerCase() == "li"){

        if(type){

            showImg(target.index);

            changeColor(target);

            type = true;

        }

    }

};

//根据参数显示对应的图片。

function showImg(inde){

    var this_li = imgli[0].index;



    //把第一个元素放到最后面。

    if(inde>this_li){

        var x = inde-this_li;

        for(var y = 0;y<x;y++){

            imgul.appendChild(imgli[0]);

        }

    }



    //把最后一个元素放到第一的位置

    if(inde<this_li){

        var x_x = this_li-inde;

        for(var g = 0;g<x_x;g++){

            imgul.insertBefore(imgli[length-1],imgli[0]);

        }

    }

}

 

 

到这里所有的代码都写好了。

下面贴上所有的代码

 

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

<style>

#banner{

width: 1000px;

height: 500px;

margin: 10px auto;

}

#content{

width: 1000px;

height: 500px;

overflow: hidden;

position: relative;

}

#ul{

height: 500px;

position: absolute;

left: 0;

}

#ul li{

list-style: none;

width: 1000px;

height: 500px;

float: left;

}

#ul img{

width: 1000px;

height: 500px;

}

.b{

width: 100px;

height: 100px;

position: absolute;

cursor: pointer;

}

.b img{

width: 100px;

height: 100px;

}

#left{

top: 200px;

left: 50px;

}

#right{

top: 200px;

right: 50px;

}

#dotul{

width: 500px;

position: relative;

left: 280px;

top: 450px;

}

#dotul li{

list-style: none;

float: left;

width: 20px;

height: 20px;

border-radius: 20px;

background-color: seagreen;

margin-left: 20px;

cursor: pointer;

}

.active{

background-color: orangered !important;

}

</style>

</head>

<body>

<div id="banner">

<div id="content">

<ul id="ul">

<li><a href="###"><img src="img/1.jpg" /></a> </li>

<li><a href="###"><img src="img/2.jpg" /></a> </li>

<li><a href="###"><img src="img/3.jpg" /></a> </li>

<li><a href="###"><img src="img/4.jpg" /></a> </li>

<li><a href="###"><img src="img/5.jpg" /></a> </li>

<li><a href="###"><img src="img/6.jpg" /></a> </li>

<li><a href="###"><img src="img/7.jpg" /></a> </li>

<li><a href="###"><img src="img/8.jpg" /></a> </li>

<li><a href="###"><img src="img/9.jpg" /></a> </li>

<li><a href="###"><img src="img/10.jpg" /></a> </li>

</ul>

<div class="dot" id="dot">

<ul id="dotul">

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

<li></li>

</ul>

</div>

</div>

<div id="btn">

<div id="left" class="b"><img src="img/prev.png"/></div>

<div id="right" class="b"><img src="img/next.png"/></div>

</div>

</div>

<script>

//定义所有需要用到的数据

var animationSpeed = 1;//一次切换的图片数(就是下一张图片的间隔)

var minSpeed = 5;//就是每次left增加或减少的数

var stopTime = 5000;//要隔多少秒开始切换下一张图片

//页面元素

var prev = document.getElementById("left");

var next = document.getElementById("right");

var banner = document.getElementById("banner");

var content = document.getElementById("content");

var imgul = document.getElementById("ul");

var imgli = document.getElementById("ul").getElementsByTagName("li");

var liwidth = document.getElementById("ul").getElementsByTagName("li")[0].offsetWidth;

var dot = document.getElementById("dot");

var dotul = document.getElementById("dotul");

var dotli = document.getElementById("dotul").getElementsByTagName('li');

var length = document.getElementById("dotul").getElementsByTagName('li').length;

var type = true;//是否可以渲染

var nextTimer = null;

var prevTimer = null;

var mainTimer = null;



imgul.style.width = liwidth*length+"px";//将ul的宽度设置为所有照片宽度的总和

//给每一个dotli添加一个index属性,方便改变小圆点的背景颜色

for (var i = 0;i<length;i++){

imgli[i].index = i;

dotli[i].index = i;

}

//给第一个小圆点加上背景

changeColor(imgli[0]);

next.onclick = function (ev) {

if (type){

liwidth = 0;

clearInterval(nextTimer);//先把上一次留下来的定时器清除(确保清除干净—)

nextTimer = setInterval(nextImg,animationSpeed);

type = false;

changeColor(imgli[1]);//改变原点颜色

}

};

function nextImg() {

imgul.style.left = "-"+liwidth+"px";

liwidth += minSpeed;

if (liwidth >= imgli[0].offsetWidth){

clearInterval(nextTimer);

imgul.appendChild(imgli[0]);//先删除imgli[0],然后加到末尾来,这样实现了循环

imgul.style.left = 0;

type = true;

}

}

prev.onclick = function (ev) {

if (type){//如果可以渲染

imgul.insertBefore(imgli[length-1],imgli[0]);//因为当前图片的位置一直都是imgli[0],所以按照循环的思想,上一张就是imli[length-1]

clearInterval(prevTimer);

liwidth = imgli[0].offsetWidth;

prevTimer = setInterval(prevImg,animationSpeed);

type = false;//因为设置了定时器,定时器在渲染,所以这时不能被渲染

changeColor(imgli[1]);//改变原点颜色

}

};



function prevImg() {

imgul.style.left = "-"+liwidth+"px";

liwidth -= minSpeed;

if (liwidth <=-1){

clearInterval(prevTimer);

imgul.style.left = 0;

type = true;//定时器已经完成渲染了,所以此时可以渲染

}

}

mainTimer = setInterval(next.onclick,5000);



function changeColor(target) {

for (var j = 0;j<length;j++){

dotli[j].className = "";

}

dotli[target.index].className = "active";

}



//为每个小圆点添加点击事件

dot.onclick = function(ev){

var ev = ev || window.event;

var target = ev.target || ev.srcElement;

if(target.nodeName.toLowerCase() == "li"){

if(type){

showImg(target.index);

changeColor(target);

type = true;

}

}

};

//根据参数显示对应的图片。

function showImg(inde){

var this_li = imgli[0].index;



//把第一个元素放到最后面。

if(inde>this_li){

var x = inde-this_li;

for(var y = 0;y<x;y++){

imgul.appendChild(imgli[0]);

}

}



//把最后一个元素放到第一的位置

if(inde<this_li){

var x_x = this_li-inde;

for(var g = 0;g<x_x;g++){

imgul.insertBefore(imgli[length-1],imgli[0]);

}

}

}



//当鼠标移入图片区域时,清除定时器。鼠标移出时恢复定时器

content.onmouseover = function (ev) {

  clearInterval(mainTimer);

};

content.onmouseout = function (ev) {

  mainTimer = setInterval(next.onclick,stopTime);

};

</script>

</body>

</html>

 

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值