1、写在最前面javascript
最近都忙一些杂七杂八的事情,复习软考、研读经典...好像都很久没写过博客了。。。css
我本身写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的,淡入淡出切换的。如今想作一个酷一点的放在博客或者我的网站,到时候能够展现本身的做品。逛了一下慕课网,发现有个旋转木马的jquery插件课程,有点酷酷的,因而就想着用原生JS封装出来。作起来才发现,没有本身想象中的那么容易。。。不啰嗦了,讲解一下实现过程吧。html
2、效果java
因为本身的服务器还没弄好。在线演示不了(ORZ...)。。。只能放一张效果图了。。。node
从图片上仍是能够看出大概效果的,我就很少说了。想看真实代码效果的,欢迎到个人github上面download代码,别忘了给个人github项目点个星星噢^_^jquery
3、实现过程git
html结构github
<div class="carrousel-main" data-setting='{"width":1000,"height":400, "carrouselWidth":750, "carrouselHeight":400, "scale":0.9, "verticalAlign":"middle"}'> <div class="carrousel-btn carrousel-btn-pre"></div> <ul class="carrousel-list"> <li class="carrousel-item"> <a href="#"><img src="img/1.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/2.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/3.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/4.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/5.jpg"></a> </ul> <div class="carrousel-btn carrousel-btn-next"></div> </div>
这个结构和通常轮播的html代码结构是同样的,稍有不一样就是,主轮播div上面有一个data-setting的属性,这个属性里面就是一些轮播效果的参数。参数的具体意义稍后再讲解。数组
css部分的代码就不贴了,最重要就是要注意元素的绝对定位,由效果图能够看出来,每张图片的位置、大小都不同,因此这些都是经过js控制的,所以须要绝对定位。下面重点讲一下js实现过程。服务器
JS实现过程
下面讲几个JS的关键步骤,作好了这几个步骤以后,应该就没有什么难点了。
①默认参数
既然是封装插件,那么确定会有一些参数的默认值须要配置的啦。这个插件中,主要有以下参数:
width:1000, //幻灯片区域的宽度 height:400, //幻灯片区域的高度 carrouselWidth:700, //幻灯片第一帧的宽度 carrouselHeight:400, //幻灯片第一帧的高度 scale:0.9,//记录显示比例关系,例如第二张图比第一张图显示的时候宽高小多少 autoPlay:true,//是否自动播放 timeSpan:3000,//自动播放时间间隔 verticalAlign:'middle' //图片对齐方式,有top\middle\bottom三种方式,默认为middle
②封装对象
由于一个网站可能有多个地方都会用到同一个轮播插件,因此封装很关键。定义了这个对象以后,若是给对象定义一个初始化方法是能够建立多个对象的,只须要把全部类相同的dom传进去就能够了。因此,个人初始化方法以下:
Carousel.init=function(carrousels){ var _this=this; //将nodeList转换为数组 var cals= toArray(carrousels);
/*由于原生JS获取全部的类,获得的是一个nodeList,是一个类数组,若是想要使用数组的方法则须要转化为真正的数组。这里toArray为转化方法。*/ cals.forEach(function(item,index,array){ new _this(item); }); }
这样的话,我在window.onload的时候,调用Carrousel.init(document.querySelectorAll('.carrousel-main'));这样就能够建立多个轮播啦!
③初始化好第一帧的位置参数
由于,第一帧以后的全部帧的相关参数都是参照第一帧来定义的,所以,定义好第一帧很关键。
setValue:function(){ this.carrousel.style.width=this.Settings.width+'px'; this.carrousel.style.height=this.Settings.height+'px'; /*左右按钮设置,这里要让左右按钮平均地瓜分轮播区域宽减去第一帧宽度以后的区域,z-index要比除第一帧外全部图片都高,而图片恰好左右分放置,所以z-index的值就是图片数量的一半。*/ var btnW=(this.Settings.width-this.Settings.carrouselWidth)/2; this.preBtn.style.width=btnW+'px'; this.preBtn.style.height=this.Settings.height+'px'; this.preBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2); this.nextBtn.style.width=btnW+'px'; this.nextBtn.style.height=this.Settings.height+'px'; this.nextBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2); //第一帧相关设置 this.carrouselFir.style.left=btnW+'px'; this.carrouselFir.style.top=this.setCarrouselAlign(this.Settings.carrouselHeight)+'px'; this.carrouselFir.style.width=this.Settings.carrouselWidth+'px'; this.carrouselFir.style.height=this.Settings.carrouselHeight+'px'; this.carrouselFir.style.zIndex=Math.floor(this.carrouselItems.length/2); },
这里,就是new对象的时候,就到dom结点中获取data-setting参数,而后更新默认参数配置。这里有个地方须要注意的,获取dom的参数不能直接以赋值的方式更新默认参数,由于用户配置参数的时候,不必定会全部参数都配置一次。若是直接赋值而用户恰好不是全部参数都配置的话就会形成参数丢失。这里我是本身写了一个相似JQuery中的$.extend方法的对象扩展方法来更新参数的。具体就不列举了,感兴趣的能够去下载。
④其余图片位置设置
这里的图片实际上就是把除第一张以外的图片,平均地分到左右两则,而左边的图片位置和右边的是不一样的,所以须要分别配置:
//设置右边图片的位置关系 var rightIndex=level; rightSlice.forEach(function(item,index,array){ rightIndex--; var i=index; rw=rw*carrouselSelf.Settings.scale;//右边的图片是按照scale比例逐渐变小的 rh=rh*carrouselSelf.Settings.scale; item.style.zIndex=rightIndex;//越往右边z-index的值越小,能够用图片数量的通常逐渐递减 item.style.width=rw+'px'; item.style.height=rh+'px'; item.style.opacity=1/(++i);//越往右边透明度越小
//这里的gap计算方法为:轮播区域减去第一帧宽度,除2,再除左边或者右边的图片张数 item.style.left=(constOffset+(++index)*gap-rw)+'px';//left的值实际上就是第一帧的left+第一帧的宽度+item的间距减去item的宽度 item.style.top=carrouselSelf.setCarrouselAlign(rh)+'px'; });
左边的设置方法相似且更为简单,就不细说了。
⑤旋转时全部图片的位置大小调整
这一步很关键,点击右边按钮下一张的即为左旋转,而点击左边按钮上一张即为右旋转。此时,咱们只须要把全部的图片当作一个环形那样,点击一次,换一次位置即完成旋转。具体为左旋转的时候,令第二张的参数等于第一张,第三张等于第二张...而最后一张等于第一张便可。右旋转的时候,令第一张的参数等于第二张,第二张的参数等于第三张...而最后一张的参数等于第一张便可。
这里就说说左旋转吧
if(dir=='left'){ toArray(this.carrouselItems).forEach(function(item,index,array){ var pre; if(index==0){//判断是否为第一张 pre=_this.carrouselLat;//让第一张的pre等于最后一张 var width=pre.offsetWidth; //获取相应参数 var height=pre.offsetHeight; var zIndex=pre.style.zIndex; var opa=pre.style.opacity; var top=pre.style.top; var left=pre.style.left; }else{ var width = tempWidth; var height = tempHeight; var zIndex = tempZIndex; var opa = tempOpacity; var top = tempTop; var left = tempLeft; } //这里须要注意,由于第二张图片是参照第一张的,而这样改变的时候,第一张是首先被改变的,所以必须先把第一张的相关参数临时保存起来。 tempWidth = item.offsetWidth; tempHeight = item.offsetHeight; tempZIndex = item.style.zIndex; tempOpacity = item.style.opacity; tempTop = item.style.top; tempLeft = item.style.left; item.style.width=width+'px'; item.style.height=height+'px'; item.style.zIndex=zIndex; item.style.opacity=opa; item.style.top=top; // item.style.left=left; animate(item,'left',left,function(){//自定义的原生js动画函数 _this.rotateFlag=true; }); }); }
这里的旋转,若是不使用一些动画过分,会显得很生硬。可是原生JS并无动画函数,这里我是本身写了一个模仿的动画函数。其原理就是获取dom原来的样式值,与新传入的值比较。用一些方法定义一个速度。我这里的速度就是用其差值除18.然定义一个计时器,参考了一下jquery源码里面的时间间隔为每13毫秒执行一次。而后才原来的样式值每次加上speed后等于传入的值的时候清楚计时器便可。具体能够看这里。
好啦,关键的地方都差很少啦,若是明白这些过程应该就很容易了!
4、总结思考
总结:
我的感受这仍是一个比较好理解的插件。若是能结合JQuery来作就至关简单了。可是用原生来写的话,仍是有一些不那么流畅的感受。应该是自定义动画比不上JQuery封装好的动画吧。
还有,这个插件由于图片须要平均分到左右两边,因而对于偶数数量的图片来讲,这里用的方法是克隆第一张,而后加到最后,造成一个奇数。
思考:
若是说有bug的话,那就是我定义了一个rotateFlag的标志去判断当前可否旋转,就是预防快速点击的时候跟不上。我在按下的时候把rotateFlag设置为false,而后在动画结束后再把rotateFlag设置为true,可是好像做用并不明显。。。但愿有关大神能够指教一下。。。
本轮播插件下载地址:个人github!