值得分享的JavaScript实现图片轮播组件

本文实例为大家分享了JavaScript实现图片轮播组件的使用方法,供大家参考,具体内容如下

效果

自动循环播放图片,下方有按钮可以切换到对应图片添加一个动画来实现图片切换。 鼠标停在图片上时,轮播停止,出现左右两个箭头,点击可以切换图片。 鼠标移开图片区域时,从当前位置继续轮播。 提供一个接口,可以设置轮播方向,是否循环,间隔时间。

对HTML、CSS的要求:

  • *必须是两个盒子嵌套,最里面的盒子需要有一个ul,图片需要被包含在li里。 *可以更改类名,同时将css文件中的相应类名替换即可。配置组件时传入正确的DOM元素即可。 *不限制图片宽度和数量,在css文件中更改数值即可。

    原理:

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

    思路:

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

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

    2.缓动函数。

    3.点亮按钮函数。

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

    5.创建箭头函数。

    6.创建按钮函数。

    7.开始轮播函数。

    8.轮播函数。

    9.停止函数。用于停止轮播。

    还有一些

    公用方法

    $():选择DOM元素。

    addClass(ele,"className"):给元素添加类名。

    removeClass(ele,"className"):移除元素的类名。

    $.add(ele,"type",fun):给一个DOM节点绑定事件。

    getCSS(ele,"prop"):获取元素相应属性的值。

    $.delegateTag("selector","tagName",fun):事件代理。

    实现:

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

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

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

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

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

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

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

    3.图片切换函数 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)。即

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

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

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

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

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

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

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

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

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

    '; } div.innerHTML=btns; addClass(div,"carousel-btn"); container.appendChild(div); }

    6.轮播函数 根据要求(顺时针、逆时针)判断要调用go("prev")还是go("next")。

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

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

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

    rush:js;"> circle=function(){ count++; if (loop||count

    7.停止函数 stop

    rush:js;"> stop=function(){ clearTimeout(begin); }

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

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

    rush:js;"> init=function(){ createBtn(); createArrow(); $.delegateTag(wrapSelec+" "+".carousel-btn","a",function(e,target){ $.prevent(e); light(target.getAttribute("index")); animate.liner(ele,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; }

    9.开始轮播函数 start

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

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

    rush:js;"> 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赋值给一个变量,然后在事件处理程序或是定时器中访问这个变量,就会获取到正确的对象。

    以init函数为例来改装:

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

    这样改装完之后,就可以创建实例了,每个实例都会有自己的属性用于记录状态,他们都共用原型中的方法

    如果采用原型继承的方式的话,可以创建一个对象作为实例的原型对象,然后创建一个函数来生产实例:

    rush:js;"> var carouselProto={};

    //把上面那些方法给这个对象
    carouselProto.light=...
    carouselProto.go=...
    carouselProto.stop=...

    //创建实例对象函数
    var carousel=function(eleSelec,wrapSelec){
    var that=Object.create(carouselProto);
    that.wrapSelec=wrapSelec;
    that.ele=$(eleSelec);
    that.container=$(wrapSelec);
    that.len=that.ele.getElementsByTagName("img").length;
    that.width=parseInt(getCSS(that.ele.getElementsByTagName("img")[0],"width"));
    return that;
    }

    //创建实例,使用组件
    var carousel1=carousel(".carousel",".carousel-Box");
    carousel1.start("forward",3,true);
    var carousel2=carousel(".carousel2",".carousel-Box2");
    carousel2.start("backward",2,true);

    性能优化:

    1.当点击的按钮刚好是当前被点亮的按钮时,依然会调用一次light和animate.liner。所以可以添加一个判断语句,如果点击的按钮刚好是正确的,就不要执行下面的了。

    rush:js;"> $.delegateTag(this.wrapSelec+" "+".carousel-btn",target){ $.prevent(e); var index=target.getAttribute("index"); if (index===that.active.getAttribute("index")) { return } that.light(index); animate.liner(that.ele,target.getAttribute("index")*that.width); });

    2.当图片切换的时候,缓动动画正在执行。如果在缓动动画还没执行完时就点击按钮或者箭头,就会进入下一次动画,于是就会出现混乱,图片错位。性能也会受到影响。为了防止这种情况发生,可以使用一个变量,用于记录缓动动画是否正在执行,没有执行的话点击按钮或箭头才会执行函数

    rush:js;"> liner=function(ele,next){ var speed=(next-ele[prop])/10,i=0; ele.animating=true; (function(){ ele[prop]+=speed; i++; if (i<10) { setTimeout(arguments.callee,60); }else{ ele.animating=false; } })(); } if (!this.ele.animating) { this.light(nextIndex); animate.liner(this.ele,nextPosition); }

    点击查看

    参考资源:

    网—— 《JavaScript:The Good Parts》

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

    相关文章

    前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
    前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
    前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
    前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
    前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
    前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...