使用JavaScript实现图片轮播效果

原理

图片轮播原理:
将一系列大小相等的图片平铺,利用css布局只显示一张图片,其他图片隐藏,通过计算偏移量利用定时器自动切换图片,或者手动点击切换图片。

样式布局

关于图片列表的布局,这里在js中使用style.left这个属性计算偏移量来进行图片的切换。而在style.left这个属性中,是无法识别样式表中写的left值,只对HTML中写的left值有效.
关于小圆点按钮,使用自定义属性index来标识第几个小圆点。后边当点击某个小圆点时,可获取该小圆点的index值来知道小圆点的位置。利用css样式使class="on"的元素颜色变亮,即点亮当前点击到的小圆点。
关于箭头切换,使用链接形式,可以添加hover伪类变换样式。<左箭头;>右箭头,html转义字符。

无缝切换:最后一张图片切换到第一张图片时,会出现一片空白,这里,借助两张辅助图来填补这片空白。
即将最后一张图片属性复制到第一张图片前,将第一张图片属性信息复制到最后一张图片后面。
并且,将第一张图片辅助图(实际上是实际显示的第5张图片隐藏起来,故设置style="left: -600px;"

<div id="container" >
        <!-- 图片列表 -->
        <div id="list" style="left: -600px">
            ![](img/5.jpg)<!-- 第一张辅助图 -->
            ![](img/1.jpg)
            ![](img/2.jpg)
            ![](img/3.jpg)
            ![](img/4.jpg)
            ![](img/5.jpg)
            ![](img/1.jpg)<!-- 第二张辅助图 -->   
        </div>
        <!-- 小圆点按钮 -->
        <div id="buttons">
            <span index="1" class="on"></span>
            <span index="2"></span>
            <span index="3"></span>
            <span index="4"></span>
            <span index="5"></span>
        </div>
        <!-- 箭头切换 -->
        <a href="javascript:;" class="arrow" id="prev">&lt;</a>
        <a href="javascript:;" class="arrow" id="next">&gt;</a>
    </div>

css结构:

  1. 绝对定位问题,图片和原点的浮动属性;
  2. overflow: hidden;//溢出隐藏
  3. 确保每个小圆点所在层置顶,(z-index:999;)这里设置为z-index:2; 另外z-index 仅能在定位元素上奏效
  4. cursor CSS属性定义鼠标指针悬浮在元素上方显示的鼠标光标。cursor: pointer显示为小手。
*{
    margin: 0;
    padding: 0;
    text-decoration: none;
}
body{
    padding: 10px;
}
#container{
    width: 600px;
    height: 400px;
    border: 3px solid #333;
    overflow: hidden;//溢出隐藏
    position: relative;//定位

}
#list{
    width: 4200px;//所有图片平铺的宽度
    height: 400px;
    border: 3px solid #333;
    position: absolute;//定位问题 利用偏移量进行切换
    /*z-index: 1;*/

    /* transition:left 2s;
    
        -moz-transition:left 2s; Firefox 4
    
        -webkit-transition:left 2s; Safari and Chrome
    
        -o-transition:left 2s; Opera */
}
#list img{
    float: left;//浮动(不用清除浮动)

}
#buttons{
    position: absolute;
    /*height: 20px;
    width: 100px*/
    /*z-index: 2;*/ //层级,使按钮置于顶层
    bottom: 25px;
    left: 250px;
}
#buttons span{
    cursor: pointer;/*小手*/
    float: left;//浮动                        
    border: 1px solid #fff;//白边框
    width: 20px;
    height: 20px;
    border-radius: 50%;//圆角
    background: #333;//黑色
    margin-right: 5px;
}
#buttons .on{
    background: orangered;//点亮成橘色
}
.arrow{
    cursor: pointer;
    display: none;//默认不显示箭头
    line-height: 39px;//垂直居中
    text-align: center;//水平居中

    font-size: 36px;
    font-weight: bold;

    width: 40px;
    height: 40px;
    position: absolute;//绝对定位
    /*z-index: 2;*/
    top: 180px;//高度
    background-color: rgba(0,0,0,0.3);
    color: #fff;
}
.arrow:hover{
    background-color: rgba(0,0,0,0.7);//鼠标移上去颜色加深
}
#container:hover .arrow{
    display: block;//鼠标移到盒子上显示箭头
}
#prev{
    left: 20px;//单独定义左箭头水平位置
} 
#next{
    right: 20px;//单独定义右箭头水平位置
}

js部分整个功能封装在window.onload事件中。

箭头切换&无限滚动&动画切换

先获取元素,添加点击事件。parseInt将字符串转换成数字。
获取style.left,是相对左边获取距离,且style.left获取的是字符串,需要用parseInt()取整转化为数字。

    next.onclick=function(){
         list.style.left=parseInt(list.style.left)-600+'px';
    }
    prev.onclick=function(){
        list.style.left=parseInt(list.style.left)+600+'px';
    }

封装在函数animate里。并实现循环切换。当切换到第一张辅助图上时,parseInt(list.style.left)的值为0,实际上应该是最后一张图片,所以归为到最后一张图片的位置上list.style.left=-3000+'px';
同理,当切换到第二张辅助图上时,parseInt(list.style.left)的值为-3600,实际上应该是第一张图片,所以归为到第一张图片的位置上list.style.left=-600+'px';

    //切换图片,利用图片的偏移量
    function animate(offset){
        var newLeft = parseInt(list.style.left)+offset;//值 图片左侧距离父元素的值
        list.style.left=newLeft+'px';//px
        // list.style.left=list.offsetLeft+offset+'px';
        if(newLeft>-600){//和第一张图片位置比较
            list.style.left=-3000+'px';//归位到第五张图片
        }
        if(newLeft<-3000){//和最后一张图片位置比较
            list.style.left=-600+'px';//归位到第一张图片
        }
        // debugger;
}

实现每次切换图片的过程中,是过渡动画切换的。
思路:通过自定义位移完一张图片的总时间time和每次位移的时间inteval,来计算图片移动一下的距离speed,直到一张图片完整的移到当前可视的盒子区域。

animate()函数内定义go()函数,首先判断图片是往哪个方向移,因为如果向左移的话,即传入的偏移量是负值,所以speed < 0,这时候图片左侧距离父元素的值parseInt(list.style.left)是越来越小的,直到为newLeft,结束动画位移,一张图片完整的切换到了可视区域。so只要parseInt(list.style.left) >newLeft,就进行动画位移;

同理,当图片向右移时,speed >0,这时候图片左侧距离父元素的值parseInt(list.style.left)是越来越大的,直到为newLeft。所以只要parseInt(list.style.left) < newLeft,就进行着动画位移。

如果满足动画位移条件会一直执行,使用定时器setTimeout(go, inteval),没隔一段时间interval执行一次go
这里使用了递归,函数内部调用该函数。

对于定时器,注意setInterval()跟setTimeout()的区别。简单来说,setInterval()执行多次,setTimeout()只执行一次。
更具体的用法可以点击链接查看区别:window.setInterval window.setTimeout

这里定义一个初始值var animated = false;,表示默认不进行动画位移,animated = true表示开始动画位置标志。并在结束动画位移操作时,将animated的值置为false。

function animate (offset) {
         animated = true;//开始动画位移
         var time = 300;//一张图片位移总时间
         var inteval = 10;//位移间隔时间
         var speed = offset/(time/inteval);//求得一次位移的距离
         var newLeft = parseInt(list.style.left) + offset;//图片左侧距离父元素的值

        //动画函数
         var go = function (){
        //监测是否具备进行动画位移的条件
        //判断左切换和右切换两种情况,都并且一张图片没有完整的占满盒子区域时。
             if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) >newLeft)) {
                   list.style.left = parseInt(list.style.left) + speed + 'px';
                   setTimeout(go, inteval);//递归
              }else {
                    list.style.left = newLeft + 'px';
                    if(newLeft>-600){
                        list.style.left=-3000+'px';//归位到第五张图片
                     }
                    if(newLeft<-3000){
                    list.style.left=-600+'px';//归位到第一张图片
                    }
                    // debugger;
                    animated = false;//结束动画位移
             }
          }
        go();//函数调用
   }

优化:加入下面代码,当传入的偏移量为0时,animate()函数里面的部分不需再执行了。

  if (offset == 0) {
                    return;
    }

按钮切换

先设置初始值index的值为1.即默认第一个小圆点时点亮着的,index用来标识第几个小圆点。点击箭头时增加或者减小index的值来实现切换小圆点的功能。注意index的取值是1~5,所以当index的值加到5时,要回归到1;index的值为1时,要切到5.

实现思路:先判断index的值,右箭头触发点击事件里如果当前index的值为5,就使index=1,否则index+=1;,同理,左箭头触发点击事件里如果当前index的值为1,就使index=5,否则index-=1;
然后点亮相应的小圆点showButton()

    var index = 1;
    next.onclick=function(){
        animate(-600);
        if(index==5){
            index=1;//使index的值不超过5
        }else{
            index+=1;//index的值随着箭头的点击进行更新
        }
        showButton();
    }

    prev.onclick=function(){
        animate(600);   
        if(index==1){
            index=5;//使index的值不小于1
        }else{
            index-=1;
        }
        showButton();

    }

优化:在两个点击事件中先加入以下代码。当检测到animated=true即进行着动画位移,不执行其他代码,避免卡顿优化性能。

if (animated) {
         return;
  }

获取小圆点var buttons = document.getElementById('buttons').getElementsByTagName('span');,不止一个,是一个数组类型。数组从0开始,所以index -1.
因为css样式中#buttons .on{background: orangered;},所以这里利用className= 'on'来点亮小圆点。


    //点亮小圆点
    function showButton(){
        buttons[index -1].className = 'on';//点亮
    }

这样会出现一个问题,切换到下一个小圆点时,前面点击过的小圆点依然是点亮着的。所有在showButton()函数中要先清除之前的样式。

for(var i=0;i<buttons.length;i++){//遍历
            if(buttons[i].className=='on'){//关闭其他亮着的小圆点
                buttons[i].className='';
                // break;//一旦监测到就退出循环
            }
        }

这样就实现了点击箭头切换图片时,对应的小圆点也跟着进行切换。

===
下面实现点击小圆点时,图片切换的功能
思路:仍然是利用图片偏移量进行切换,偏移值为-600乘以要点击的小圆点的index值减去当前小圆点的index值)

因为要对每一个小圆点添加点击事件,先对其进行遍历。
首先获取要点击的(目标)小圆点的自定义属性值parseInt(this.getAttribute('index')),即在html布局中span标签里index的属性。

getAttribute()既可以获取自定义属性值也可以获取原本就存在的属性的值。

不要忘记更新当前的index值index=myIndex;

    //点击小圆点进行切换图片
    for (var i = 0; i < buttons.length; i++) {
        buttons[i].onclick = function(){//对每个小圆点添加点击事件
        var myIndex = parseInt(this.getAttribute('index'));//获取要点击的小圆点的自定义index属性值
        console.log(myIndex);
        var offset = -600*(myIndex-index);//求偏移值
        animate(offset);
        index=myIndex;//更新到当前的index值
        showButton();
        }
        // debugger;
    }

优化:在每个小圆点的点击事件中加入以下代码。

点击小圆点时,当检测到animated=true即进行动画位移的过程中,不触发该点击事件即不执行后面代码,避免卡顿优化性能。

当检测到this.className=='on'即点击当前的小圆点,也不需要执行后面代码,优化性能。

if (animated) {
     return;
 }
if(this.className=='on'){
     return;    
 }  

自动播放

利用定时器setTimeout()setInterval,实现每隔3秒自动播放下一张图片。并在鼠标移到var container = document.getElementById('container');上时清楚浮动。

用到一种回调函数的使用方式,如果stop(),stop方法就被执行了,但是如果写方法名stop,是事件触发时才会调用stop方法

var interval = 3000;
var timer;
function play() {
        timer = setTimeout(function () {
              next.onclick();
              play();
        }, interval); 
}
function stop() {
        clearTimeout(timer);
 }
/*
    //每隔3秒自动播放下一张图片
    function play(){
        timer = setInterval(function(){
            next.onclick();
        },3000);
    }
    //清除定时器
    function stop(){
        clearInterval(timer);
    }
*/

container.onmouseover = stop;
container.onmouseout = play;
play();

最后,如果不进行一些优化,可能会出现疯狂点击会使图片错位等情况。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 通过学习,我理解了图片轮播原理,学习了setTimeout()、setInterval()函数设置定时器与清除定时...
    McRay阅读 2,025评论 0 7
  • 进入前端将近一年了,js还是很弱,突发奇想写一个轮播图,就找到了这个博主的材料,和大家分享。 轮播图的原理: 一系...
    FRRRR阅读 3,576评论 0 11
  • 前端学习时间不长,最近看完了第一遍高设,想着试着写一点东西,于是有了这个还不算好的轮播效果。(学习出处为慕课网) ...
    JellyFive阅读 615评论 0 6
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,629评论 1 92
  • 是否有感冒可能了?
    时間阅读 147评论 0 0