文档章节

原生JS实现"旋转木马"效果的图片轮播插件

LuckyWinty
 LuckyWinty
发布于 2016/04/24 22:49
字数 2330
阅读 343
收藏 8

一、写在最前面

最近都忙一些杂七杂八的事情,复习软考、研读经典...好像都好久没写过博客了。。。

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

二、效果

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

 

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

三、实现过程

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

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

四、总结思考

总结:

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

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

思考:

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

 

本轮播插件下载地址:https://github.com/LuckyWinty/carrousel

 

© 著作权归作者所有

LuckyWinty
粉丝 10
博文 24
码字总数 32476
作品 0
广州
前端工程师
私信 提问
使用原生js以两种方式制作一个精美的轮播图(下)

展示界面 & github源码 (这里可以实现PC端模拟移动端左右滑动图片切换的效果) github源码(包含两种方式实现轮播图的源码) 项目预览 前言 如何用原生js实现一个简单的轮播图呢?前面我已经用...

子银_
09/02
0
0
手把手教你封装JavaScript插件

我们可能已经用过很多JS插件,比如著名的轮播图插件Swiper.js,滚动条插件iScroll.js等等,用起来非常方便,大大提高了我们的工作效率。那么它们基本实现原理是怎样的呢?我们又该如何DIY一个...

前端王睿
2018/08/29
0
0
封装一个简单的原生js焦点轮播图插件

轮播图实现的效果为,鼠标移入左右箭头会出现,可以点击切换图片,下面的小圆点会跟随,可以循环播放。本篇文章的主要目的是分享封装插件的思路。 轮播图的我一开始是写成非插件形式实现的效...

daisy,gogogo
2018/08/18
0
0
手把手教你用原生JavaScript造轮子(2)——轮播图

通过上一篇文章的学习,我们基本掌握了一个轮子的封装和开发流程。那么这次将带大家开发一个更有难度的项目——轮播图,希望能进一步加深大家对于面向对象插件开发的理解和认识。 So, Let's ...

csdoker
2018/08/12
0
0
记一个JavaScript图片轮播思路与代码

说在前头 喜欢并学习前端,一路摸爬滚打过来,现在算算也快满一年的,每天或多或少都会来“拜读”大家的写的文章,学习与感悟了不少,作为一名要变的更强的前端小哥哥,在这个节点上,也想写...

柚子先生
2018/08/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

为构建社交关系链手淘都做了啥?

作者|王卫(泓冰) 出品|阿里巴巴新零售淘系技术部 01、淘宝社交关系推荐的背景 1、互联网下半场到来:互联网的下半场,人口红利消失,各大平台需要对用户做精细化运营,用户的增长和留存是每一...

阿里云官方博客
9分钟前
3
0
Iaas/Paas/Saas有何区别,一个故事告诉你

云计算有三种服务模式,IaaS,PaaS和SaaS。单从英文全称去理解,他们分别是“基础设施即服务”“平台即服务”和“软件即服务”。 这样翻译过来可不好理解,但是我们可以举个例子。现在我们就以...

JEPaaS云平台
17分钟前
3
0
温度传感器怎么测好坏

  温度传感器也就是负温度系数热敏电阻,温度越高,电阻越小,测量时先看其阻值能不能根据温度的变化而变,再看其变化的阻值是不是在标定的范围之内。   有以下四种方法;   1、若是有...

仙溪
17分钟前
3
0
zk中ZooKeeperServer解析

内部类 ChangeRecord 处理PrepRP和FinalRP之间的信息 static class ChangeRecord { ChangeRecord(long zxid, String path, StatPersisted stat, int childCount, List<ACL> acl) {......

writeademo
27分钟前
3
0
LNMP---安装worrdpress、discuz,域名重定向,用户认证,nginx访问日志

4.34 安装wordpress 4.35 安装discuz 4.36 域名重定向 4.37 用户认证 4.38 nginx访问日志 一、安装wordpress 创建博客: 添加一个博客的虚拟主机 blog.tobe.com.conf 做如下更改 安装博客wor...

tobej
29分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部