原生JS实现旋转木马式图片轮播插件


Posted in Javascript onApril 25, 2016

本人自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的,淡入淡出切换的。现在想做一个酷一点的放在博客或者个人网站,到时候可以展示自己的作品。逛了一下慕课网,发现有个旋转木马的jquery插件课程,有点酷酷的,于是就想着用原生JS封装出来。做起来才发现,没有自己想象中的那么容易。。。不??铝耍?步庖幌率迪止?贪伞?/p>

二、效果

由于自己的服务器还没弄好。在线演示不了(ORZ...),只能放一张效果图了。

原生JS实现旋转木马式图片轮播插件 

从图片上还是可以看出大概效果的,我就不多说了。想看真实代码效果的,欢迎到我的github上面download代码,别忘了给我的github项目点个星星噢^_^

三、实现过程

html结构

<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); <br> /*因为原生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);//越往右边透明度越小<br>  //这里的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后等于传入的值的时候清楚计时器即可。具体可以看这里。

好啦,关键的地方都差不多啦,如果明白这些过程应该就很容易了!

四、总结思考

总结:

个人感觉这还是一个比较好理解的插件。如果能结合JQuery来做就相当简单了。但是用原生来写的话,还是有一些不那么流畅的感觉。应该是自定义动画比不上JQuery封装好的动画吧。

还有,这个插件因为图片需要平均分到左右两边,于是对于偶数数量的图片来说,这里用的方法是克隆第一张,然后加到最后,形成一个奇数。

思考:

如果说有bug的话,那就是我定义了一个rotateFlag的标志去判断当前能否旋转,就是预防快速点击的时候跟不上。我在按下的时候把rotateFlag设置为false,然后在动画结束后再把rotateFlag设置为true,但是好像作用并不明显,希望有关大神可以指教一下,大家共同进步。

以上就是本文的全部内容,更多内容请参考:javascript图片轮播效果汇总 ,谢谢大家的阅读。

Javascript 相关文章推荐
网站上面有这种切换效果
Jun 26 Javascript
js判断选择的时间是否大于今天的代码
Aug 20 Javascript
JS复制到剪贴板示例代码
Oct 30 Javascript
javaScript 页面自动加载事件详解
Feb 10 Javascript
javascript结合ajax读取txt文件内容
Dec 05 Javascript
javascript数组去重方法汇总
Apr 23 Javascript
js内置对象处理_打印学生成绩单的简单实现
Sep 24 Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
Apr 01 Javascript
Jquery把获取到的input值转换成json
May 15 jQuery
Vue中computed与methods的区别详解
Mar 24 Javascript
vue 使用vue-i18n做全局中英文切换的方法
Oct 29 Javascript
vue实现在线翻译功能
Sep 27 Javascript
第四章之BootStrap表单与图片
Apr 25 #Javascript
第五章之BootStrap 栅格系统
Apr 25 #Javascript
详解Bootstrap插件
Apr 25 #Javascript
Bootstrap每天必学之折叠(Collapse)插件
Apr 25 #Javascript
第六章之辅组类与响应式工具
Apr 25 #Javascript
第七章之菜单按钮图标组件
Apr 25 #Javascript
第九章之路径分页标签与徽章组件
Apr 25 #Javascript
You might like
Apache, PHP在Windows 9x/NT下的安装与配置 (二)
2006/10/09 PHP
PHP中new static()与new self()的区别异同分析
2014/08/22 PHP
PHP网站开发中常用的8个小技巧
2015/02/13 PHP
PHP读书笔记整理_结构语句详解
2016/07/01 PHP
Yii统计不同类型邮箱数量的方法
2016/10/18 PHP
多广告投放代码 推荐
2006/11/13 Javascript
javascript实现的网页局布刷新效果
2008/12/01 Javascript
extjs 学习笔记 四 带分页的grid
2009/10/20 Javascript
让mayfish支持mysqli数据库驱动的实现方法
2010/05/22 Javascript
ASP.NET jQuery 实例17 通过使用jQuery validation插件校验ListBox
2012/02/03 Javascript
js获取class的所有元素
2013/03/28 Javascript
jquery用get实现ajax在ie里面刷新不进入后台解决方法
2013/08/12 Javascript
JS控制日期显示的小例子
2013/11/23 Javascript
js读取并解析JSON类型数据的方法
2015/11/14 Javascript
实例解析jQuery插件EasyUI最常用的表单验证规则
2015/11/29 Javascript
BootStrap的select2既可以查询又可以输入的实现代码
2017/02/17 Javascript
ES6中class类用法实例浅析
2017/04/06 Javascript
简单实现JavaScript弹幕效果
2020/08/27 Javascript
AngularJS监听ng-repeat渲染完成的两种方法
2018/01/16 Javascript
详解如何解决vue开发请求数据跨域的问题(基于浏览器的配置解决)
2018/11/12 Javascript
vue中eslintrc.js配置最详细介绍
2018/12/21 Javascript
vue实现form表单与table表格的数据关联功能示例
2019/01/29 Javascript
vue实现购物车结算功能
2020/06/18 Javascript
vue 数据双向绑定的实现方法
2021/03/04 Vue.js
python基础教程之实现石头剪刀布游戏示例
2014/02/11 Python
python实现猜单词小游戏
2020/05/22 Python
Python中断多重循环的思路总结
2019/10/04 Python
numpy.ndarray 实现对特定行或列取值
2019/12/05 Python
基于python和flask实现http接口过程解析
2020/06/15 Python
台湾良兴购物网:EcLife
2019/12/01 全球购物
State Cashmere官网:半零售价可持续蒙古羊绒
2020/02/26 全球购物
网络、C以及其他硬件方面的面试题
2016/08/23 面试题
Java如何调用外部Exe程序
2015/07/04 面试题
群众路线教育党课主持词
2014/04/01 职场文书
有关骆驼祥子的读书笔记
2015/06/26 职场文书
Python入门之使用pandas分析excel数据
2021/05/12 Python