原生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 相关文章推荐
JS 文字符串转换unicode编码函数
May 30 Javascript
改变文件域的样式实现思路同时兼容ie、firefox
Oct 23 Javascript
解决extjs grid 不随窗口大小自适应的改变问题
Jan 26 Javascript
BootStrap下拉框在firefox浏览器界面不友好的解决方案
Aug 18 Javascript
获取select的value、text值的简单示例(jquery与javascript)
Dec 07 Javascript
javascript数组去重方法分析
Dec 15 Javascript
jQuery获取选中单选按钮radio的值
Dec 27 Javascript
vue中axios处理http发送请求的示例(Post和get)
Oct 13 Javascript
angularjs select 赋值 ng-options配置方法
Feb 28 Javascript
vue1.0和vue2.0的watch监听事件写法详解
Sep 11 Javascript
Element-ui之ElScrollBar组件滚动条的使用方法
Sep 14 Javascript
JavaScript命令模式原理与用法实例详解
Mar 10 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
Zend framework处理一个http请求的流程分析
2010/02/08 PHP
PHP高级编程实例:编写守护进程
2014/09/02 PHP
Javascript中的常见排序算法
2007/03/27 Javascript
常用的JQuery函数及功能小结
2016/03/24 Javascript
利用Angularjs和Bootstrap前端开发案例实战
2016/08/27 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
2016/11/01 Javascript
nodejs实现发出蜂鸣声音(系统报警声)的方法
2017/01/18 NodeJs
JS实现简易刻度时钟示例代码
2017/03/11 Javascript
微信小程序 共用变量值的实现
2017/07/12 Javascript
微信小程序使用wxParse解析html的方法教程
2018/07/06 Javascript
使用Vue实现图片上传的三种方式
2018/07/17 Javascript
详解在网页上通过JS实现文本的语音朗读
2019/03/28 Javascript
vue实现跳转接口push 转场动画示例
2019/11/01 Javascript
Vue数字输入框组件示例代码详解
2020/01/15 Javascript
Vue 中使用 typescript的方法详解
2020/02/17 Javascript
[57:59]EG vs Secret 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
Python3实现的字典、列表和json对象互转功能示例
2018/05/22 Python
Python3.6基于正则实现的计算器示例【无优化简单注释版】
2018/06/14 Python
Python功能点实现:函数级/代码块级计时器
2019/01/02 Python
解决python-docx打包之后找不到default.docx的问题
2020/02/13 Python
将 Ubuntu 16 和 18 上的 python 升级到最新 python3.8 的方法教程
2020/03/11 Python
python爬虫用scrapy获取影片的实例分析
2020/11/23 Python
浅析移动设备HTML5页面布局
2015/12/01 HTML / CSS
Godiva巧克力英国官网:比利时歌帝梵巧克力
2018/08/28 全球购物
计算机专业推荐信范文
2013/11/20 职场文书
农场厂长岗位职责
2013/12/28 职场文书
本科毕业生求职自荐信
2014/04/09 职场文书
大学优秀班集体申报材料
2014/05/23 职场文书
安全月宣传标语
2014/10/07 职场文书
检讨书格式
2015/01/23 职场文书
大学生心理健康活动总结
2015/05/08 职场文书
党小组考察意见
2015/06/02 职场文书
罗马假日观后感
2015/06/08 职场文书
反邪教学习心得体会
2016/01/15 职场文书
2016年乡镇综治宣传月活动总结
2016/03/16 职场文书
Nginx的反向代理实例详解
2021/03/31 Servers