移動輪播圖我看到兩類,javascript
一款是無線天貓的m.tmall.com和攜程,實現了無縫輪播。css
一款是蘑菇街的,沒有實現無縫輪播。html
我本身重寫一個,相似天貓。html5
1.頁面代碼java
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>基於jQuery的移動輪播圖(支持觸屏)</title> 6 <meta name="viewport" content="maximum-scale=1,initial-scale=1,user-scalable=0"> 7 8 <style type="text/css"> 9 10 img 11 { 12 border:0; 13 *display:inline; 14 } 15 li 16 { 17 border:0; 18 list-style-type :none; 19 } 20 ul 21 { 22 list-style:none; 23 margin:0; 24 padding:0; 25 } 26 body{ 27 overflow-x:hidden; 28 margin:0 auto; 29 padding:0; 30 width: 100%; 31 height: 100%; 32 } 33 .WSCSlideWrapper{ 34 width:100%; 35 position: relative; 36 margin:0 auto; 37 //cursor:move; 38 } 39 #WSCSlideWrapperTwo{ 40 width:50%; 41 position: relative; 42 margin:10px auto; 43 //cursor:move; 44 } 45 46 </style> 47 <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/jquery-1.8.2.min.js"></script> 48 49 <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/touchslide-1.1.js"></script> 50 </head> 51 <body> 52 53 54 <div class="WSCSlideWrapper" id="WSCSlideWrapper" > 55 56 <div> 57 58 <a href="http://www.baidu.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1.jpg" /></a> 59 <a href="http://m.tmall.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/2.jpg" /></a> 60 <a href="http://huaban.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/3.jpg" /></a> 61 </div> 62 63 </div> 64 65 <div class="WSCSlideWrapper" id="WSCSlideWrapperTwo" > 66 <div> 67 <a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (1).jpg" /></a> 68 <a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (2).jpg" /></a> 69 <a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (3).jpg" /></a> 70 <a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (4).jpg" /></a> 71 </div> 72 73 </div> 74 <script type="text/javascript"> 75 76 $(document).ready(function(){ 77 78 $('.WSCSlideWrapper').height($('.WSCSlideWrapper').width()*0.3); 79 $('#WSCSlideWrapperTwo').height($('#WSCSlideWrapperTwo').width()*1.5); 80 $('.WSCSlideWrapper').touchslide({timecontrol:3000,animatetime:300,direction:'left',navshow:true,canvassuport:true}); 81 }); 82 83 84 </script> 85 </body> 86 </html>
2.js插件代碼jquery
1 /* 2 * touchslide 1.1 3 * Copyright (c) 2014 BowenLuo http://www.luobo.com/ 4 * Date: 2014-06-08 5 * Example:$('.WSCSlideWrapper').touchslide({timecontrol:3000,animatetime:300,direction:'left',navshow:true,canvassuport:true}); 6 * Update:增長對IE9+等非Safari內核瀏覽器的鼠標拖動圖片功能 7 */ 8 (function($){ 9 $.fn.touchslide = function(options){ 10 var defaults = { 11 timecontrol:3000,//圖片停留時間 12 animatetime:300, //圖片滑動所需時間 13 direction:'left', //輪播方向 14 navshow:true,//是否顯示圖片導航欄 15 canvassuport:true//圖片導航欄是否開啓cavas繪製圓 16 } 17 var options = $.extend(defaults, options); 18 var timecontrol = options.timecontrol||3000; 19 var animatetime = options.animatetime||300; 20 var direction = options.direction||'left'; 21 var navshow = options.navshow; 22 this.each(function(){ 23 var slideWrapper=$(this); 24 var slideImgWrapper = slideWrapper.children('div:first'); 25 var slideAs = slideImgWrapper.children('a'); 26 var slideImgs = slideAs.children('img'); 27 var imgcount = slideImgs.length; 28 var imgcountrealy = slideImgs.length; 29 var navimgs; 30 var circlewrapper; 31 var circles; 32 var canvassuport = true; 33 var circler = 0; 34 if(imgcount>1){ 35 $((slideImgWrapper.html().split("/a>")[0]+"/a>"+slideImgWrapper.html().split("/a>")[1]+"/a>")).insertAfter(slideAs.last()); 36 if(navshow){ 37 $("<div class='navimgs'></div>").insertAfter(slideImgWrapper); 38 navimgs = slideWrapper.children('div:last'); 39 navimgs.append("<div class='circlewrapper'></div>"); 40 circlewrapper = navimgs.children('div:first'); 41 for(var i=0;i<imgcountrealy;i++){ 42 circlewrapper.append("<canvas class='circle' width='15' height='15'></canvas>"); 43 } 44 circles = circlewrapper.children('canvas'); 45 var myCanvas = circles[1]; 46 if (!myCanvas.getContext) 47 { 48 canvassuport =false; 49 }else 50 { 51 canvassuport =options.canvassuport; 52 } 53 } 54 } 55 slideAs = slideImgWrapper.children('a'); 56 slideImgs = slideAs.children('img'); 57 imgcount = slideImgs.length; 58 var slideWrapperWidth = slideWrapper.width(); 59 var slideWrapperHeight = slideWrapper.height(); 60 slideWrapper.css({"overflow":"hidden","width":slideWrapperWidth,"height":slideWrapperHeight}); 61 slideImgWrapper.css({'position':"absolute","z-index":"1","overflow":"hidden","width":slideWrapperWidth*imgcount,"height":slideWrapperHeight}); 62 slideAs.css({'position':"relative","overflow":"hidden","float":"left","width":slideWrapperWidth,"height":slideWrapperHeight}); 63 slideImgs.css({'position':"relative","z-index":"1","width":slideWrapperWidth,"height":slideWrapperHeight}); 64 if(typeof(navimgs)!=='undefined'){ 65 if(navshow){ 66 navimgs.css({"position":"absolute","z-index":"3","overflow":"hidden","display":"block","width":slideWrapperWidth,"height":slideWrapperWidth*0.05,"bottom":"0"}); 67 if(slideWrapperWidth*0.05>15){ 68 navimgs.height(24); 69 } 70 circlewrapper.css({"position":"relative","overflow":"hidden","width":(slideWrapperWidth*0.05*imgcountrealy),"height":slideWrapperWidth*0.04,"margin":"auto"}); 71 circles.css({'position':"relative","float":"left","max-width":15,"max-height":15,"margin-left":slideWrapperWidth*0.01}); 72 if(slideWrapperWidth*0.03>15){ 73 circler=15; 74 }else{ 75 circler = slideWrapperWidth*0.03; 76 } 77 circles.attr("width",circler); 78 circles.attr("height",circler); 79 canvacircle(0); 80 for(var i=0;i<circles.length;i++){ 81 navclick(i); 82 } 83 }else{ 84 navimgs.css({"display":"none"}); 85 } 86 } 87 if(imgcount<4){ 88 return; 89 } 90 slideImgWrapper.css({'left':-slideWrapperWidth}); 91 var st; 92 var sts; 93 sts = setTimeout(function(){ 94 timedCount(); 95 },timecontrol); 96 97 slideWrapper.hover(function(){ 98 stopAll(); 99 }, 100 function(){ 101 sts = setTimeout(function(){ 102 timedCount(); 103 },timecontrol); 104 }); 105 mouseDrag(slideWrapper); 106 touchDrag(slideWrapper); 107 108 function timedCount() 109 { 110 if(direction=='left'){ 111 turnleft(); 112 }if(direction=='right'){ 113 turnright(); 114 } 115 clearTimeout(st); 116 st=setTimeout(function(){ 117 timedCount(); 118 },timecontrol); 119 } 120 121 function stopCount() 122 { 123 if (st !=""){ 124 clearTimeout(st); 125 } 126 } 127 128 function stopAll() 129 { 130 stopCount(); 131 clearTimeout(sts); 132 slideImgWrapper.stop(true); 133 } 134 135 function navclick(navnum){ 136 circlewrapper.children('canvas:eq('+navnum+')').click(function(e){ 137 scideimgskip(navnum+1); 138 }) 139 } 140 141 function scideimgskip(imgnum){ 142 stopAll(); 143 turnleftwidth = imgnum*slideWrapperWidth; 144 slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){ 145 var imgnum = turnleftwidth/slideWrapperWidth-1; 146 if(imgnum==0){ 147 imgnum=imgcountrealy; 148 } 149 if((imgnum-imgcountrealy)==0){ 150 imgnum=0; 151 } 152 canvacircle(imgnum); 153 }); 154 } 155 156 function canvacircle(canvanum){ 157 circles.attr("width",circler); 158 circles.attr("height",circler); 159 for(var i=0;i<circles.length;i++){ 160 if(canvassuport){ 161 var navCanvas=circles[i]; 162 var cxt=navCanvas.getContext("2d"); 163 if(i==canvanum){ 164 cxt.fillStyle="#0182D7"; 165 }else{ 166 cxt.fillStyle="#ddd"; 167 } 168 cxt.arc(circler*0.5,circler*0.5,circler*0.5,0,Math.PI*2,true); 169 cxt.closePath(); 170 cxt.fill(); 171 }else{ 172 circles.css("background","#ddd"); 173 circlewrapper.children('canvas:eq('+canvanum+')').css("background","#0182D7"); 174 } 175 176 } 177 } 178 179 var turnleftwidth = slideWrapperWidth; 180 function turnleft(){ 181 turnleftwidth = turnleftwidth+slideWrapperWidth; 182 if(turnleftwidth>(imgcount-2)*slideWrapperWidth){ 183 slideImgWrapper.css({'left':0}); 184 turnleftwidth = slideWrapperWidth; 185 } 186 slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){ 187 var imgnum = turnleftwidth/slideWrapperWidth-1; 188 if(imgnum==0){ 189 imgnum=imgcountrealy; 190 } 191 if((imgnum-imgcountrealy)==0){ 192 imgnum=0; 193 } 194 canvacircle(imgnum); 195 }); 196 } 197 function turnright(){ 198 turnleftwidth = turnleftwidth-slideWrapperWidth; 199 if(turnleftwidth==0){ 200 slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)}); 201 turnleftwidth = slideWrapperWidth*(imgcount-2); 202 } 203 slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){ 204 var imgnum = turnleftwidth/slideWrapperWidth-1; 205 if(imgnum==0){ 206 imgnum=imgcountrealy; 207 } 208 if((imgnum-imgcountrealy)==0){ 209 imgnum=0; 210 } 211 canvacircle(imgnum); 212 }); 213 } 214 215 var distanceX=0; 216 217 function toLeft(){ 218 if(turnleftwidth>(imgcount-3)*slideWrapperWidth){ 219 slideImgWrapper.css({"left":distanceX}); 220 turnleftwidth = 0; 221 } 222 turnleft(); 223 sts = setTimeout(function(){ 224 timedCount(); 225 },timecontrol); 226 } 227 228 function toRight(){ 229 if(turnleftwidth==slideWrapperWidth){ 230 slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)+distanceX}); 231 turnleftwidth = slideWrapperWidth*(imgcount-1); 232 } 233 turnright(); 234 sts = setTimeout(function(){ 235 timedCount(); 236 },timecontrol); 237 } 238 239 function mouseDrag($element) { 240 var eventEle = $element; 241 var stx = etx = curX = 0; 242 var MAction = false; 243 var ahrefs = []; 244 for(var i=0;i<slideAs.length;i++){ 245 if(typeof(slideImgWrapper.children('a:eq('+i+')').attr('href'))!=='undefined'){ 246 ahrefs.push(slideImgWrapper.children('a:eq('+i+')').attr('href')); 247 } 248 } 249 eventEle.mouseover(function(){ 250 for(var i=0;i<slideAs.length;i++){ 251 if(typeof(slideImgWrapper.children('a:eq('+i+')').attr('href'))!=='undefined'){ 252 slideImgWrapper.children('a:eq('+i+')').attr('href',ahrefs[i]); 253 } 254 } 255 }); 256 eventEle.mousemove(function(event){ 257 if(MAction){ 258 var changeX = event.pageX-stx; 259 slideImgWrapper.css({"left":-turnleftwidth+changeX}); 260 distanceX = changeX; 261 } 262 event.preventDefault(); 263 }).mousedown(function(event){ 264 stopAll(); 265 MAction = true; 266 stx = event.pageX; 267 event.preventDefault(); 268 }); 269 eventEle.mouseup(function(event){ 270 etx = event.pageX; 271 curX = etx-stx; 272 MAction = false; 273 if(curX>5){ 274 slideAs.attr("href","javascript:void(0)"); 275 toRight(); 276 } 277 if(curX<-5){ 278 slideAs.attr("href","javascript:void(0)"); 279 toLeft(); 280 } 281 event.preventDefault(); 282 }); 283 } 284 285 function touchDrag($element) { 286 var gundongX = 0; 287 var gundongY = 0; 288 var moveEle = $element; 289 var stx = sty = etx = ety = curX = curY = 0; 290 291 var ImgWidth_arr = []; 292 for (var i = 0; i < imgcount; i++) { 293 ImgWidth_arr.push(i * slideWrapperWidth); 294 } 295 296 moveEle.on("touchstart", function(event) { //touchstart 297 stopAll(); 298 var event = event.originalEvent; 299 gundongX = 0; 300 gundongY = 0; 301 // 元素當前位置 302 etx = parseInt(getT3d(moveEle, "x")); 303 ety = parseInt(getT3d(moveEle, "y")); 304 // 手指位置 305 stx = event.touches[0].pageX; 306 sty = event.touches[0].pageY; 307 }); 308 moveEle.on("touchmove", function(event) { 309 var event = event.originalEvent; 310 // 防止拖動頁面 311 event.preventDefault(); 312 313 // 手指位置 減去 元素當前位置 就是 要移動的距離 314 gundongX = event.touches[0].pageX - stx; 315 gundongY = event.touches[0].pageY - sty; 316 317 // 目標位置 就是 要移動的距離 加上 元素當前位置 318 curX = gundongX + etx; 319 curY = gundongY + ety; 320 slideImgWrapper.css({"left":-turnleftwidth+curX}); 321 distanceX = curX; 322 }); 323 moveEle.on("touchend", function(event) { 324 //alert(gundongX); 325 if(Math.abs(gundongX)>5){ 326 event.preventDefault(); 327 328 // 手指接觸屏幕的位置 329 var oriX = etx; 330 var oriY = ety; 331 // 手指離開屏幕的位置 332 etx = curX; 333 ety = curY; 334 var slidePosition = 0; 335 for (var i = 0; i < imgcount - 1; i++) { 336 if (Math.abs(etx) > ImgWidth_arr[i]) { 337 338 if (oriX > etx) { 339 // 左滑 340 toLeft(); 341 } else { 342 // 右滑 343 toRight(); 344 } 345 } 346 } 347 } 348 349 }); 350 351 function getT3d(elem, ename) { 352 var elem = elem[0]; 353 var str1 = elem.style.webkitTransform; 354 if (str1 == "") return "0"; 355 str1 = str1.replace("translate3d(", ""); 356 str1 = str1.replace(")", ""); 357 var carr = str1.split(","); 358 359 if (ename == "x") return carr[0]; 360 else if (ename == "y") return carr[1]; 361 else if (ename == "z") return carr[2]; 362 else return ""; 363 } 364 } 365 }); 366 }; 367 })(jQuery);
在線演示web
3.總體思路canvas
a.建立顯示窗口,顯示容器大小位置自定義;vim
b.創立圖片容器,經過改變圖片容器的位置來改變顯示窗口中展現的圖片。瀏覽器
難點在於如何改變圖片容器位置來顯示須要的圖片和無縫輪播。能夠想象一下之前的膠帶式電影,若是放映速度慢下來就跟圖片輪播相似了。因此能夠把圖片容器當作膠帶,圖片就是其中的一幀圖像,顯示窗口就是電影屏幕。
若是以一個顯示窗口的寬爲一個單位,咱們把圖片水平排放在圖片容器中,每張圖片剛好佔用一個顯示窗口的寬高,有多少張圖片,圖片容器的寬就爲多少個單位寬。而後使圖片向左移動一個單位的距離,就能夠展現下一張圖片了。爲了使圖片展現效果更美觀,我用了jquery的動畫效果animate()來改變圖片容器的位置。若是設定間隔多少時間圖片容器左移一個單位,達到最後一張圖片時,圖片容器恢復到原始位置,進行下一輪移動。這樣,就能夠實現圖片的水平輪播了。至於無縫輪播,我採起的作法是把前兩張圖片複製一份,放到全部圖片的最後面。首次顯示第二張圖片,當移動到倒數第二張圖片時,在下一次移動時先改變容器的left,讓第一張圖片被顯示出來,由於這個動做很快,看起來好像並無進行任何操做(達到欺騙眼球的效果,呵呵),而後使用animate顯示第二張圖片,在視覺上實現無縫輪播。從第二張圖片右移時也與此相似。這樣作的主要目的是爲了確保左右都有能被展現的圖片,確保不會顯示空白,以實現無縫切換。這裏,會用到的主要知識點有:
(1).setTimeout和clearTimeout:
用於延遲執行、循環執行和終止循環。setTimeout延遲執行肯定圖片的顯示時間,循環執行爲了自動展現下一張圖片。當須要中止輪播的時候就能夠用clearTimeout來終止循環了。關於setTimeout和clearTimeout的具體用法,能夠參照代碼,這裏就再也不贅述了。
(2).jquery選擇器:
無需多說,全部jquery動做的基礎。
(3).jquery操做css:
爲了保證使用的簡單性,只需肯定顯示容器的樣式(需確保overflow:hidden;插件中已設置),其子元素包括圖片容器(這裏只支持div標籤slideWrapper.children('div:eq(0)'))和圖片及其連接的樣式都在插件中肯定,包括:保證圖片水平排列,大小剛好爲顯示窗口的大小;肯定圖片容器的大小剛好容下全部圖片。
(4).jquery添加元素insertAfter:
複製前兩張圖片到全部圖片的最後面$((slideImgWrapper.html().split("/div>")[0]+"/div>"+slideImgWrapper.html().split("/div>")[1]+"/div>")).insertAfter(slideAWra.last())。
(5).jquery動畫效果animate:
1 var turnleftwidth = slideWrapperWidth; 2 function turnleft(){ 3 turnleftwidth = turnleftwidth+slideWrapperWidth; 4 if(turnleftwidth>(imgcount-2)*slideWrapperWidth){ 5 slideImgWrapper.css({'left':0}); 6 turnleftwidth = slideWrapperWidth; 7 } 8 slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime); 18 } 19 function turnright(){ 20 turnleftwidth = turnleftwidth-slideWrapperWidth; 21 if(turnleftwidth==0){ 22 slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)}); 23 turnleftwidth = slideWrapperWidth*(imgcount-2); 24 } 25 slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime); 35 }
其中imgcount爲進行圖片複製後圖片的元素個數,slideWrapperWidth爲顯示窗口的寬。 turnleft()用於無縫左移,turnright()用於無縫右移。
如今來講說觸屏支持。主要是用了jquery的on方法監聽touch事件。具體怎麼寫,無非就是設置初始觸摸位置,而後監聽滑動的位置,根據水平滑動的具體實時改變圖片容器的left,實現拖拽的效果。滑動結束後根據結束時的位置與初始位置的差判斷左滑仍是右滑,再來改變圖片容器的left,使圖片正好居中顯示。跟PC端的鼠標拖拽相似。說到鼠標拖拽,不得不噴倆句。通常拖拽元素,基本都是mousedown、mousemove、mouseup三部曲。可是碰上圖片就頭疼了,特別是這圖片的父親仍是a標籤。mousedown沒問題,mousemove能一個三五步,mousemove出問題mouseup也就失效了。弄了半天,終於經過 event.preventDefault()實現了對大部分瀏覽器的支持。廢話很少說,讓你們一塊兒糾結下。
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8"> 3 <head> 4 <meta charset="UTF-8"> 5 <style> 6 body{ 7 overflow-x:hidden; 8 margin:0 auto; 9 padding:0; 10 width: 100%; 11 height: 100%; 12 } 13 .aWrapper{ 14 position: relative; 15 margin:0 auto; 16 width:400px; 17 height:600px; 18 overflow:hidden; 19 //float:left; 20 } 21 .testa{ 22 position: relative; 23 margin:0 auto; 24 width:400px; 25 height:600px; 26 //float:left; 27 } 28 .testimg{ 29 position: absolute; 30 width:400px; 31 height:600px; 32 z-index:0; 33 } 34 .imgmask{ 35 position: relative; 36 width:400px; 37 height:600px; 38 z-index:1; 39 opacity:0.2; 40 background:#333; 41 } 42 </style> 43 </head> 44 <body> 45 <div class="aWrapper"> 46 <a href="http://www.baidu.com" class="testa"> 47 <img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (1).jpg" class="testimg"/> 48 <div class='imgmask'></div> 49 </a> 50 </div> 51 </body> 52 </html>
上面測試頁面只有在Safari內核的瀏覽器(如Chrome)下才可以拖拽的,並且當圖片遮罩層的position設置爲absolute或者a標籤設置float時都會失效,實在是搞不明白。並且要說一下能夠很容易的阻止事件向上冒泡,有什麼辦法觸發父元素事件是不要觸發子元素的該事件麼?仍是以上面的測試頁面爲例,要拖拽aWrapper的div,就要設置該元素的mousedown、mousemove、mouseup事件。可是這裏有一個問題,在mousedown和mouseup以後會觸發click事件,致使觸發子元素a標籤的click而跳轉頁面。若是僅僅在mouseup時設置a標籤的click返回false,那麼這個連接就永遠失效了。具體處理方法,你們仍是看代碼吧,反正被我搞得複雜得很,說多了都是淚。
最後說說這個導航欄,就是下面的方方圈圈,用來顯示第幾張和點擊跳轉的。若是直接在頁面上編寫,問題倒還簡單。在JS中就複雜多了。爲了確保插件的獨立性,除了對jquery的依賴外,我不想它有任何其餘依賴。因此通常用圖片來表示狀態的方法就行不通了。我用的是html5的canvas繪製圓形。若是瀏覽器不支持或者擔憂瀏覽器消耗的話,能夠關閉掉,直接用背景色表示,只是只能爲方塊塊了。反正我以爲我本身弄的既不美觀又不優雅,你們就當參照吧。