原生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实现带省略号的分页
Apr 27 Javascript
JS实现不规则TAB选项卡效果代码
Sep 16 Javascript
JavaScript保留关键字汇总
Dec 01 Javascript
详解Jquery 遍历数组之$().each方法与$.each()方法介绍
Jan 09 Javascript
Vue2单一事件管理组件通信
May 09 Javascript
温故知新——JavaScript中的字符串连接问题最全总结(推荐)
Aug 21 Javascript
node.js学习之断言assert的使用示例
Sep 28 Javascript
JS实现读取xml内容并输出到div中的方法示例
Apr 19 Javascript
说说node中的可读流和可写流的区别
Jun 01 Javascript
微信小程序实现文字无限轮播效果
Dec 28 Javascript
vue 搭建后台系统模块化开发详解
May 01 Javascript
基于Electron实现桌面应用开发代码实例
Jul 07 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
phpfans留言版用到的install.php
2007/01/04 PHP
php遍历所有文件及文件夹的方法深入解析
2013/06/08 PHP
php中opendir函数用法实例
2014/11/15 PHP
使用Zttp简化Guzzle 调用
2017/07/02 PHP
Jquery chosen动态设置值实例介绍
2013/08/08 Javascript
两个select多选模式的选项相互移动(示例代码)
2014/01/11 Javascript
js操作输入框提示信息且响应鼠标事件
2014/03/25 Javascript
JavaScript保留两位小数的2个自定义函数
2014/05/05 Javascript
基于jquery插件实现拖拽删除图片功能
2020/08/27 Javascript
有关JavaScript中call()和apply() 的一些理解
2016/05/20 Javascript
初识简单却不失优雅的Vue.js
2016/09/12 Javascript
微信小程序 五星评价功能的实现
2017/03/09 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
2017/03/09 Javascript
手动用webpack搭建第一个ReactApp的示例
2018/04/11 Javascript
解决包含在label标签下的checkbox在ie8及以下版本点击事件无效果兼容的问题
2019/10/27 Javascript
[01:02:47]EG vs Secret 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.21.mp4
2020/07/19 DOTA
用实例说明python的*args和**kwargs用法
2013/11/01 Python
关于Tensorflow中的tf.train.batch函数的使用
2018/04/24 Python
python3字符串操作总结
2019/07/24 Python
pytorch中torch.max和Tensor.view函数用法详解
2020/01/03 Python
python实现tail -f 功能
2020/01/17 Python
PyTorch 导数应用的使用教程
2020/08/31 Python
纯css3实现效果超级炫的checkbox复选框和radio单选框
2014/09/01 HTML / CSS
美国精油公司:Plant Therapy
2019/05/17 全球购物
法国最大的在线眼镜店:EasyLunettes
2019/08/26 全球购物
c++工程师面试问题
2013/08/04 面试题
汇智创新科技发展有限公司
2015/12/06 面试题
简述进程的启动、终止的方式以及如何进行进程的查看
2014/02/20 面试题
岗位竞聘演讲稿
2014/01/10 职场文书
离婚协议书包括哪些内容
2014/10/16 职场文书
2014幼儿园家长工作总结
2014/11/10 职场文书
商场圣诞节活动总结
2015/05/06 职场文书
2019幼儿教师求职信(3篇)
2019/09/20 职场文书
python3 hdf5文件 遍历代码
2021/05/19 Python
5种方法告诉你如何使JavaScript 代码库更干净
2021/09/15 Javascript
mysql幻读详解实例以及解决办法
2022/06/16 MySQL