朋友让帮忙找个原生JS写的带缓动效果的图片幻灯,类似Tmall首页的效果,找了一圈后发现网上JS写的图片幻灯很多,相关的jQuery插件也很多,但用原生JS写的带缓动效果的却不多。没办法只好自己动手,现在把代码分享给大家,希望对大家有用。
代码中的缓动公式用了司徒正美博客中整理的代码:http://www.cnblogs.com/rubylouvre/archive/2009/09/17/1567607.html
缓动公式的推导主要利用了物理中的加速度知识,推荐过程可以看看这篇文章:http://floatyears.info/javascript-animation-easing
HTML部分:
<div id="J-Slide"> <ul class="JSlide-list"> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_01.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_02.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_03.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_04.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_05.jpg" alt=""/></li> </ul> <ul class="JSlide-num"> <li class="current">1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <div class="JSlide-mask"></div> </div>
这部分比较简单,跟Tmall首页效果一样,几张图片,左下角是图片索引,并有一个半透明的遮罩层。
CSS部分:
body,ul,li{ margin:0; padding:0; } ul{ list-style:none; } #J-Slide{ width:600px; height:400px; position:relative; margin:50px auto; overflow:hidden; } #J-Slide .JSlide-list{ position:absolute; width:3000px; left:0; top:0; } #J-Slide .JSlide-list li{ float:left; } #J-Slide .JSlide-list li img{ width:600px; height:400px; } #J-Slide .JSlide-num{ position:absolute; left:0; bottom:0; height:30px; padding:5px; width:100%; z-index:10; } #J-Slide .JSlide-num li{ width:30px; height:30px; margin-left:10px; float:left; font-size:16px; color:white; background:#716584; line-height:30px; text-align:center; cursor:pointer; border-radius:15px; } #J-Slide .JSlide-mask{ position:absolute; left:0; background:black; bottom:0; width:100%; height:40px; opacity:0.3; filter:Alpha(opacity = 30); z-index:1; } #J-Slide .JSlide-num .current{ background:#B91919; }
CSS部分比较简单,直接用absolute定位。
JavaScript库部分:
(function(){ /* *参数说明: *id 必须 *picwidth 可选 *speed 可选 * *作者:artwl *出处:http://artwl.cnblogs.com */ var JCP_Slide=function(id,picwidth,speed){ if(!(this instanceof JCP_Slide)) return new JCP_Slide(id,picwidth,speed); var obj=document.getElementById(id), childs=obj.getElementsByTagName("ul"); this.author="artwl"; this.jslideList=childs[0]; this.jslideNums=childs[1].children; this.speed= speed || 5000; this.picwidth= picwidth || (obj.currentStyle ? parseFloat(obj.currentStyle.width) : parseFloat(document.defaultView.getComputedStyle(obj,null).width)); this.currentIndex=0; this.distance=this.picwidth; this.currentLeftPos=0; this.runHandle=null; this.len=this.jslideNums.length; } JCP_Slide.prototype={ bindMouse:function(){ var self=this; for(var i=0;i<this.len;i++){ this.jslideNums[i].onmouseover=(function(index){ return function(){ self.currentIndex=index; clearInterval(self.runHandle); var prev=-1; for(var k=0;k<self.len;k++){ if(self.jslideNums[k].className === "current") prev = k; self.jslideNums[k].className = k === index ? "current" : "" ; } if(prev != index){ self.distance=(prev - index)*self.picwidth; self.currentLeftPos = -prev * self.picwidth; self.transition(self.jslideList,{field:'left',begin:self.currentLeftPos,change:self.distance,ease:self.easeOutCirc}) } } })(i); this.jslideNums[i].onmouseout=function(){ self.autoRun(); } } }, autoRun:function(){ var self=this; this.runHandle=setInterval(function(){ self.distance=-self.picwidth; for(var k=0;k<self.len;k++){ self.jslideNums[k].className = "" ; } self.currentIndex++; self.currentIndex%=5; self.jslideNums[self.currentIndex].className = "current"; self.currentLeftPos = -(self.currentIndex-1) * self.picwidth; if(self.currentIndex == 0){ self.distance = (self.len-1)*self.picwidth; self.currentLeftPos = -self.distance; } self.transition(self.jslideList,{field:'left',begin:self.currentLeftPos,change:self.distance,ease:self.easeOutCirc}); },self.speed); }, easeOutCirc:function(pos){ return Math.sqrt(1 - Math.pow((pos-1), 2)) }, transition:function(el){ el.style.position = "absolute"; var options = arguments[1] || {}, begin = options.begin,//开始位置 change = options.change,//变化量 duration = options.duration || 500,//缓动效果持续时间 field = options.field,//必须指定,基本上对top,left,width,height这个属性进行设置 ftp = options.ftp || 50, onStart = options.onStart || function(){}, onEnd = options.onEnd || function(){}, ease = options.ease,//要使用的缓动公式 end = begin + change,//结束位置 startTime = new Date().getTime();//开始执行的时间 onStart(); (function(){ setTimeout(function(){ var newTime = new Date().getTime(),//当前帧开始的时间 timestamp = newTime - startTime,//逝去时间 delta = ease(timestamp / duration); el.style[field] = Math.ceil(begin + delta * change) + "px"; if(duration <= timestamp){ el.style[field] = end + "px"; onEnd(); } else { setTimeout(arguments.callee,1000/ftp); } },1000/ftp); })(); }, play:function(){ this.bindMouse(); this.autoRun(); } }; window.JCP_Slide=JCP_Slide; })();
这个JS库是核心,入口有三个参数,第一个是最外层的div的id(必须),第二个参数是图片宽度(可选),默认为最外层DIV宽度,第三个参数为自动切换的时间间隔(可选),默认为5秒。
bindMouse是绑定鼠标的悬浮和移出事件,autoRun是让图片正动切换,play方法调用了这两个方法。
easeOutCirc是一个先快后慢的缓动公式,transition是缓动函数,这两个方法的用法请参考 司徒正美 的博客:http://www.cnblogs.com/rubylouvre/archive/2009/09/17/1567607.html
调用示例:
window.onload=function(){ JCP_Slide("J-Slide").play(); };
完整代码为:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> New Document </title> <style type="text/css"> body,ul,li{ margin:0; padding:0; } ul{ list-style:none; } #J-Slide{ width:600px; height:400px; position:relative; margin:50px auto; overflow:hidden; } #J-Slide .JSlide-list{ position:absolute; width:3000px; left:0; top:0; } #J-Slide .JSlide-list li{ float:left; } #J-Slide .JSlide-list li img{ width:600px; height:400px; } #J-Slide .JSlide-num{ position:absolute; left:0; bottom:0; height:30px; padding:5px; width:100%; z-index:10; } #J-Slide .JSlide-num li{ width:30px; height:30px; margin-left:10px; float:left; font-size:16px; color:white; background:#716584; line-height:30px; text-align:center; cursor:pointer; border-radius:15px; } #J-Slide .JSlide-mask{ position:absolute; left:0; background:black; bottom:0; width:100%; height:40px; opacity:0.3; filter:Alpha(opacity = 30); z-index:1; } #J-Slide .JSlide-num .current{ background:#B91919; } </style> <script> (function(){ /* *参数说明: *id 必须 *picwidth 可选 *speed 可选 * *作者:artwl *出处:http://artwl.cnblogs.com */ var JCP_Slide=function(id,picwidth,speed){ if(!(this instanceof JCP_Slide)) return new JCP_Slide(id,picwidth,speed); var obj=document.getElementById(id), childs=obj.getElementsByTagName("ul"); this.author="artwl"; this.jslideList=childs[0]; this.jslideNums=childs[1].children; this.speed= speed || 5000; this.picwidth= picwidth || (obj.currentStyle ? parseFloat(obj.currentStyle.width) : parseFloat(document.defaultView.getComputedStyle(obj,null).width)); this.currentIndex=0; this.distance=this.picwidth; this.currentLeftPos=0; this.runHandle=null; this.len=this.jslideNums.length; } JCP_Slide.prototype={ bindMouse:function(){ var self=this; for(var i=0;i<this.len;i++){ this.jslideNums[i].onmouseover=(function(index){ return function(){ self.currentIndex=index; clearInterval(self.runHandle); var prev=-1; for(var k=0;k<self.len;k++){ if(self.jslideNums[k].className === "current") prev = k; self.jslideNums[k].className = k === index ? "current" : "" ; } if(prev != index){ self.distance=(prev - index)*self.picwidth; self.currentLeftPos = -prev * self.picwidth; self.transition(self.jslideList,{field:'left',begin:self.currentLeftPos,change:self.distance,ease:self.easeOutCirc}) } } })(i); this.jslideNums[i].onmouseout=function(){ self.autoRun(); } } }, autoRun:function(){ var self=this; this.runHandle=setInterval(function(){ self.distance=-self.picwidth; for(var k=0;k<self.len;k++){ self.jslideNums[k].className = "" ; } self.currentIndex++; self.currentIndex%=5; self.jslideNums[self.currentIndex].className = "current"; self.currentLeftPos = -(self.currentIndex-1) * self.picwidth; if(self.currentIndex == 0){ self.distance = (self.len-1)*self.picwidth; self.currentLeftPos = -self.distance; } self.transition(self.jslideList,{field:'left',begin:self.currentLeftPos,change:self.distance,ease:self.easeOutCirc}); },self.speed); }, easeOutCirc:function(pos){ return Math.sqrt(1 - Math.pow((pos-1), 2)) }, transition:function(el){ el.style.position = "absolute"; var options = arguments[1] || {}, begin = options.begin, change = options.change, duration = options.duration || 500, field = options.field, ftp = options.ftp || 50, onStart = options.onStart || function(){}, onEnd = options.onEnd || function(){}, ease = options.ease, end = begin + change, startTime = new Date().getTime(); onStart(); (function(){ setTimeout(function(){ var newTime = new Date().getTime(), timestamp = newTime - startTime, delta = ease(timestamp / duration); el.style[field] = Math.ceil(begin + delta * change) + "px"; if(duration <= timestamp){ el.style[field] = end + "px"; onEnd(); } else { setTimeout(arguments.callee,1000/ftp); } },1000/ftp); })(); }, play:function(){ this.bindMouse(); this.autoRun(); } }; window.JCP_Slide=JCP_Slide; })(); window.onload=function(){ JCP_Slide("J-Slide").play(); }; </script> </head> <body> <div id="J-Slide"> <ul class="JSlide-list"> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_01.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_02.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_03.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_04.jpg" alt=""/></li> <li><img src="http://images.cnblogs.com/cnblogs_com/artwl/357654/o_05.jpg" alt=""/></li> </ul> <ul class="JSlide-num"> <li class="current">1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <div class="JSlide-mask"></div> </div> </body> </html>
运行效果:
- 1
- 2
- 3
- 4
- 5