CODE大全
版权声明:本文为博主原创文章,未经博主允许不得转载。

JavaScript 实现图片自动轮播组件

发布时间:『 2016-11-21 17:37』  博客类别:WEB前端  阅读(1454) 评论(0)

我们经常会遇到一些需要图片轮播的场景,或者幻灯插件、滑动幻灯片、js轮播幻灯特效来丰富我们的体验和效果。目前市面上的插件有很多,举不胜举。今天我们从原理上来分析一下图片轮播组件的实现和具体的实现代码。

图片轮播的特点:

  • 自动循环播放图片,下方有按钮可以切换到对应图片。

  • 添加一个动画来实现图片切换。

  • 鼠标停在图片上时,轮播停止,出现左右两个箭头,点击可以切换图片。

  • 鼠标移开图片区域时,从当前位置继续轮播。

  • 可以设置轮播方向,是否循环,间隔时间。

对HTML、CSS的要求:

<div class="carousel-box">
    <div class="carousel">
        <ul class="clearfix" >
            <li><img src="img/carousel01.jpg" alt=""></li>
            <li><img src="img/carousel02.jpg" alt=""></li>
            <li><img src="img/carousel03.jpg" alt=""></li>
            <li><img src="img/carousel04.jpg" alt=""></li>
            <li><img src="img/carousel05.jpg" alt=""></li>
            <li><img src="img/carousel06.jpg" alt=""></li>
        </ul>
    </div>
</div>
  • 必须是两个盒子嵌套,最里面的盒子需要有一个ul,图片需要被包含在li里。

  • 可以更改类名,同时将css文件中的相应类名替换即可。配置组件时传入正确的DOM元素即可。

  • 不限制图片宽度和数量,在css文件中更改数值即可。

/*需要更改的值*/
.carousel img{  
    width: 600px;
    height: 400px;
}
.carousel,
.carousel-box {
    width: 600px;  /*单张图片宽度*/
    height: 400px; /*单张图片高度*/
}
.carousel ul{
    width: 3600px; /*单张图片宽度x图片数量*/
}

图片轮播组件的原理

将所有图片横向排列,最外层容器和包裹容器设置overflow:hidden。最外层容器用于按钮和箭头的定位。利用包裹容器的scrollLeft属性控制显示哪张图片。

实现思路

想要实现这些功能,应该有以下一些方法:

  • 图片切换函数。接受一个参数,表示滚动方向。调用缓动函数切换图片。调用切换按钮图标函数点亮相应的按钮。

  • 缓动函数。

  • 点亮按钮函数。

  • 初始化函数。用于绑定事件,创建按钮和箭头,初始化最初位置。

  • 创建箭头函数。

  • 创建按钮函数。

  • 开始轮播函数。

  • 轮播函数。

  • 停止函数。用于停止轮播。

还有一些公用方法:$():选择DOM元素。addClass(ele,"className"):给元素添加类名。removeClass(ele,"className")移除元素的类名。$.add(ele,"type",fun):给一个DOM节点绑定事件。getCSS(ele,"prop"):获取元素相应属性的值。$.delegateTag("selector","tagName","type",fun):事件代理。

实现图片轮播效果

假设有6张图片,每张图片宽度为600px。按照功能的独立性来完成:

缓动函数 liner

缓动函数的作用是一点一点的改变目标元素的属性值,直到达到目标值。使用它的元素可能是水平轮播的图片,也可能是垂直轮播的图片,也可能是一个想从页面左端到达页面右端的小盒子。所以它应该接收四个参数(目标元素,要改变的属性值,目标值,移动次数)。

liner=function(ele,prop,next,num){
    var speed=(next-ele[prop])/num,
        i=0;
    (function(){
        ele[prop]+=speed;
        i++;
        if (i<num) {
            setTimeout(arguments.callee,30);
        }
    })();    
}

点亮按钮函数 light

点亮按钮本质上就是给按钮添加一个active类,熄灭按钮就是给按钮移除active类。

那么如何知道当前按钮是哪一个呢?

最简单的方法是直接获取,所以可以给每个按钮添加一个index属性,当需要点亮按钮时,将要点亮的按钮的index传给这个函数即可。

那么如何知道要熄灭的按钮是哪一个呢?

最简单的方法也是直接获取,所以可以在作用域链末端添加一个变量active,记住当前亮着的按钮,这个函数直接将他熄灭就可以了。

light=function(index){
    removeClass(active,"active");
    active=$(this.wrapSelec+" "+"[index="+index+"]");
    addClass(active,"active");
}

图片切换函数 go

需要计算出下一个scrollLeft的值:

如果是向左移动的话,scrollLeft应该-600,如果已经是0,就切换为3000.所以是ele.scrollLeft===0?width*(len-1):ele.scrollLeft-width;

如果是向右移动的话,scrollLeft应该+600,即0——>600,600——>1200,...,3000——>0。这里可以像上面那样用判断,也可以用一个公式next=(cur+distance)%(distance*num)。即(ele.scrollLeft+width)%(width*len)

需要获得下一个要被点亮的按钮的index:

和计算scrollLeft的思路一样,往左移动:index===0? len-1:index-1; 往右移动:(index+1)%len

go=function(dire){
    var index=active.getAttribute("index")-0,
        nextIndex,
        nextPosition;
    if (dire==="next") {
        nextIndex=(index+1)%len;
        nextPosition=(ele.scrollLeft+width)%(width*len);
    }else{
        nextIndex=index===0? len-1:index-1,
        nextPosition=ele.scrollLeft===0?width*len:ele.scrollLeft-width;
    }
    light(nextIndex);
    animate.liner(ele,"scrollLeft",nextPosition);   
}

其中的len(图片总数)、width(图片宽度)、ele(包裹容器)也会被其他函数访问,所以也添加到作用域链末端。

len=ele.getElementsByTagName("img").length

width=parseInt(getCSS(ele.getElementsByTagName("img")[0],"width");

ele=$(eleSelec),eleSelec是包裹容器的selector,比如.carousel

创建箭头函数 createArrow

创建一个向左的箭头,绑定事件处理函数,用于向左移动。创建一个向右的箭头,绑定事件处理函数,用于向右移动。

createArrow=function(){
    var prev=document.createElement("div"),
        next=document.createElement("div");
    prev.appendChild(document.createTextNode("<"));
    next.appendChild(document.createTextNode(">"));
    prev.className="arrow prev";
    next.className="arrow next";    
    container.appendChild(prev);
    container.appendChild(next);
    addClass(container,"hide");
    $.add(next,"click",function(){
        go("next");
    });
    $.add(prev,"click",function(){
        go("prev");
    });
}

container代表最外层容器,也会被其他函数访问,所以也添加到作用域链末端。

container=$(wrapSelec),wrapSelec是最外层容器的selector,比如.carousel-box

创建按钮函数 createBtn

给每个按钮添加一个index用于点亮和熄灭,给按钮组添加一个类名用于设置样式和获取它:

createBtn=function(){
    var div=document.createElement("div"),
        btns='';
    for(var i=0;i<len;i++){
        btns+='<a href="#" index="'+i+'"></a>';
    }
    div.innerHTML=btns;
    addClass(div,"carousel-btn");
    container.appendChild(div);
}

轮播函数

根据要求(顺时针、逆时针)判断要调用go("prev")还是go("next")。

如果要求循环,则再次调用自己。如果不循环,则在轮播一轮后停止。

所以这里需要一个变量来判断方向,一个变量来判断是否循环,一个变量来计数。

所以又有四个变量被加到作用域链末端。direction、loop、count、begin用于清除定时器。

circle=function(){
    count++;
    if (loop||count<len) {
        if (direction==="forward") {
            go("next");
        }else{
            go("prev");
        }
    }
    begin=setTimeout(arguments.callee,t);
}

停止函数 stop

stop=function(){
    clearTimeout(begin);
}

初始化函数 init

如果是第一次使用轮播,则创建按钮和箭头,并给按钮绑定click事件处理程序(获取点击的按扭index点亮它,切换到相应图片),然后根据顺时针或逆时针来展示相应的图片和按钮。

所以这里又需要有一个变量加在作用域链末端,用于表示是否已经初始化。

init=function(){
    createBtn();
    createArrow();
    $.delegateTag(wrapSelec+" "+".carousel-btn","a","click",function(e,target){
        $.prevent(e);
        light(target.getAttribute("index"));
        animate.liner(ele,"scrollLeft",target.getAttribute("index")*width);
    });
    $.add(container,"mouseenter",function(){
        stop();
        removeClass(container,"hide");
    });
    $.add(container,"mouseleave",function(){
        addClass(container,"hide");
        begin=setTimeout(circle,t); 
    });if (direction==="forward") {
        light(0);
    }else{
        light(len-1);
        ele.scrollLeft=width*(len-1);
    }
    haveStart=true;
}

开始轮播函数 start

这个函数当做接口,用于控制轮播方向,间隔时间,和是否循环。计数器归零。

因为可能重复的开始轮播,所以每次开始之前都需要清除定时器。

start=function(dir,th,lo){
    stop();
    count=0;
    direction=dir;
    t=th*1000;
    loop=lo;
    if (!haveStart) {
        init();
    }
    begin=setTimeout(circle,t);
}

到这里,所有需要用到的函数已经写完了,如果把这些函数和那些需要的变量扔到一个函数里,把外层容器盒包裹容器的类名或ID传给它,这个函数返回一个包含start和stop方法的对象,这个组件就可以使用了。

但是有一个问题,这个函数只有一个,也就是说,一个页面只能有一个轮播实例。所以,如果想要一个页面能有两个轮播实例都用这个组件的话,就不能把它们扔到一个函数里。那么就只能放到对象里。每个对象有自己的变量,他们共用一组方法。

那么,这些变量就不能直接访问了,需要通过对象的属性访问,即this。

这时候就会出现问题,this是会指向调用它的那个环境,所以当那些变量在事件处理程序中,或是在定时器中被访问的时候,就不能用this,而是要创建一个闭包。

即,在能获取到this时,将this赋值给一个变量,然后在事件处理程序或是定时器中访问这个变量,就会获取到正确的对象。

源代码地址:https://github.com/mamengyi/Baidu/tree/master/2015_Spring/task0002/carousel

参考资源:

http://www.cnblogs.com/LiveWithIt/p/6078619.html
http://www.imooc.com/learn/18
《JavaScript:The Good Parts》


——— 全文完 ———
如有版权问题,请联系532009913@qq.com。
关键字:   JavaScript     图轮播特效     幻灯插件     js幻灯片     图片画廊  
评论信息
暂无评论
发表评论
验证码: 
Powered by CODE大全 | 鄂ICP备14009759号-2 | 网站留言 Copyright © 2014-2016 CODE大全 版权所有