原生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 相关文章推荐
node.js中的console.info方法使用说明
Dec 09 Javascript
js操作css属性实现div层展开关闭效果的方法
May 11 Javascript
微信小程序 教程之wxapp 视图容器 view
Oct 19 Javascript
bootstrap paginator分页前后台用法示例
Jun 17 Javascript
JavaScript实现树的遍历算法示例【广度优先与深度优先】
Oct 26 Javascript
微信小程序实现天气预报功能
Jul 18 Javascript
JS正则表达式封装与使用操作示例
May 15 Javascript
Vue2.0实现组件之间数据交互和通信操作示例
May 16 Javascript
微信小程序云开发修改云数据库中的数据方法
May 18 Javascript
JavaScript内置对象math,global功能与用法实例分析
Jun 10 Javascript
Node.js+Vue脚手架环境搭建的方法步骤
Mar 08 Javascript
js前端面试常见浏览器缓存强缓存及协商缓存实例
Jun 21 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
第四章 php数学运算
2011/12/30 PHP
windows服务器中检测PHP SSL是否开启以及开启SSL的方法
2014/04/25 PHP
thinkphp区间查询、统计查询与SQL直接查询实例分析
2014/11/24 PHP
老司机传授Ubuntu下Apache+PHP+MySQL环境搭建攻略
2016/03/20 PHP
PHP Header失效的原因分析及解决方法
2016/11/16 PHP
PHP的自定义模板引擎
2017/03/24 PHP
jquery 操作DOM的基本用法分享
2012/04/05 Javascript
js实现文本框中输入文字页面中div层同步获取文本框内容的方法
2015/03/03 Javascript
jQuery实现动画效果circle实例
2015/08/06 Javascript
JavaScript String 对象常用方法总结
2016/04/28 Javascript
jQuery简单实现title提示效果示例
2016/08/01 Javascript
vue组件实例解析
2017/01/10 Javascript
解决nodejs中使用http请求返回值为html时乱码的问题
2017/02/18 NodeJs
jQuery层级选择器_动力节点节点Java学院整理
2017/07/04 jQuery
JS实现前端页面的搜索功能
2018/06/12 Javascript
js+html实现点名系统功能
2019/11/05 Javascript
Python生成pdf文件的方法
2014/08/04 Python
Python数组定义方法
2016/04/13 Python
pandas创建新Dataframe并添加多行的实例
2018/04/08 Python
python的xpath获取div标签内html内容,实现innerhtml功能的方法
2019/01/02 Python
Python3标准库总结
2019/02/19 Python
python点击鼠标获取坐标(Graphics)
2019/08/10 Python
详解Python实现进度条的4种方式
2020/01/15 Python
python怎么删除缓存文件
2020/07/19 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
2020/09/09 Python
Python监听剪切板实现方法代码实例
2020/11/11 Python
加拿大租车网站:Enterprise Rent-A-Car
2018/07/26 全球购物
高中学生期末评语
2014/04/25 职场文书
银行柜员求职自荐书
2014/06/18 职场文书
大学感恩节活动总结
2015/05/05 职场文书
单位工资证明范本
2015/06/12 职场文书
致接力运动员加油稿
2015/07/21 职场文书
初中思品教学反思
2016/02/20 职场文书
Docker官方工具docker-registry案例演示
2022/04/13 Servers
JavaScript设计模式之原型模式详情
2022/06/21 Javascript
微软Win11 全新照片应用面向 Dev预览版推出 新版本上手体验图集
2022/09/23 数码科技