深度揭密輪播插件核心代碼的實現過程

深度揭密輪播插件核心代碼的實現過程

  輪播效果在網頁中用的不少,swiper是其中最有表明性的做品,它支持水平和豎直滑動,還有反彈效果,兼容移動端和pc端。固然代碼量也是至關大的,單是js就有5300行(3.4.0的未縮版本),若不考慮代碼利用率和加載速度直接就用了,在移動端比較慎重,好比京東(m.jd.com)的輪播就沒有用它,而是本身實現了相似的功能,代碼量不多的樣子(格式化以後看起來二三百行左右的樣子)。那麼這個功能若是本身來實現,要怎麼作呢?javascript

準備工做

1. 準備幾張圖片(我這裏放了四張)css

2. 搭建目錄結構(html+css+images+js)html

3. 編寫代碼,實現初始狀態的顯示效果java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<! DOCTYPE  html>
< html >
< head >
     < meta  charset="utf-8">
     < meta  name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
     < title >輪播</ title >
     < link  rel="stylesheet" type="text/css" href="slider.css">
     < script  src="slider.js"></ script >
</ head >
< body >
     < div  id="slider" class="slider-wrapper">
         < ul  class="slider-items">
             < li  class="slider-item">< img  src="images/pic21.gif" alt="1"></ li >
             < li  class="slider-item">< img  src="images/pic22.gif" alt="2"></ li >
             < li  class="slider-item">< img  src="images/pic23.gif" alt="3"></ li >
             < li  class="slider-item">< img  src="images/pic24.gif" alt="4"></ li >
         </ ul >
     </ div >
     < script >
         Slider('#slider',{});
     </ script >
</ body >
</ html >

寫幾行樣式,先讓頁面有一種滾動前的初始畫面。android

作好這個靜態頁,能夠幫助咱們在開發過程當中預覽效果,方便查找問題,欣賞製做過程帶來的樂趣。ios

在線預覽css3

搭建程序骨架

接下來就是寫js了,先搭一個程序的架子,我這裏仿一下jQ的無new式設計(實際上是本身在內部自動實現new的過程)git

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
;(  function ( global, factory ) {
     "use strict" ;
     if  typeof  module ===  "object"  &&  typeof  module.exports ===  "object"  ) {
         module.exports = global.document ?
             factory( global,  true  ) :
             function ( w ) {
                 if  ( !w.document ) {
                     throw  new  Error(  "Slider requires a window with a document"  );
                 }
                 return  factory( w );
             };
     else  {
         factory( global );
     }
 
// Pass this if window is not defined yet
} )(  typeof  window !==  "undefined"  ? window :  this function ( window, noGlobal ){
     "use strict" ;
          function  Slider( selector, options ) {
         return  new  Slider.init( selector, options );
     }
     Slider.init= function (selector, params){
         next: function (){},<br>             prev: function (){},<br>             move: function (){}
        }<br>     Slider.init.prototype = Slider.prototype = {<br>      <br>       };
        return  Slider
});

架子搭好以後,先停下來喝口水,思考一下,最終咱們的這個插件要實現哪些功能。github

    1. 點擊左、右箭頭能夠控制滾動web

    3. 能夠向左、向右拖拽滑動 

    4. 返彈效果

    5. 自動輪播效果

    6. 頁碼指示

這些功能該怎麼實現?

先畫幾張草圖,在紙上模擬一下這個過程,搞明白以後,再用代碼來讓計算機執行。下圖中的藍框表明顯示器的寬度,紅框表明圖片所在容器的實際寬度。我只要移動紅框,那麼在屏幕上看起來,就會有輪播滾動的效果。原理看起來是否是很簡單?本着先易後難,按部就班的做戰方針,先不考慮循環滾動。假設屏幕上顯示的是圖片1,此時只要把紅框往左移一個屏的寬度,那麼就會顯示2,再移一屏,就能夠顯示3. 向右滾動正好相反。

移動能夠用css3的transform:translate3d來作,也能夠用js變化left/top來作,用translate3d來作的核心代碼以下:

1
2
3
4
5
6
7
8
9
10
11
function  translate3d(element,x,y) {
         x = x === undefined ? 0 : x;
         y = y === undefined ? 0 : x;
         element.style[ '-webkit-transform' ] =  'translate3d(-' +x+ 'px,' +y+ 'px,0px)' ;
         element.style[ 'transform' ] =  'translate3d(-' +x+ 'px,' +y+ 'px,0px)' ;
     }
     
     function  transition(element,time){
         element.style[ '-webkit-transition-duration' ] = time+ 'ms' ;
         element.style[ 'transition-duration' ] = time+ 'ms' ;
     }

x控制左右移動,y控制豎直移動(本例中暫不考慮),z固定(0px). 當x移動的距離是正數的時候,向左滾動--prev,爲負數的時候向右滾動--next

1
2
3
4
5
6
7
8
9
10
11
fn.next =  function (){
         var  activeIndex = ++ this .activeIndex;
         translate3d( this .wrap,activeIndex* this .slideWidth);
         transition( this .wrap, this .params.speed);
     }
 
fn.prev =  function (){
         var  activeIndex = -- this .activeIndex;
         translate3d( this .wrap,activeIndex* this .slideWidth);
         transition( this .wrap, this .params.speed);
     }

因爲圖片數量是有限的,不能一直滾動,若是到頭了,須要作一些處理。所以須要判斷activeIndex(當前顯示的圖片索引)的值。若是到了最右邊就不能再容許滾動了。

1
2
3
var  activeIndex =  this .lastIndex--;<br> if (activeIndex >  this .lastIndex){
      return ;
}

同理,到了最左邊,也不能繼續往左滾動了(聽起來是一句很是正確的廢話)

1
2
3
4
var  activeIndex = -- this .activeIndex;
if (activeIndex <  this .firstIndex){
   return ;
}

如今要考慮自動滾動的狀況,若是是自動輪播的狀況,那就不能直接return; 要麼當到達最右邊的時候,activeIndex賦成firstIndex,當達到最左邊的時候,activeIndex賦成lastIndex; 這樣作的實際效果看起來就是像盪鞦韆同樣,這顯然不是咱們想要的效果。要麼跳到最前面從新開始,這作出來的實際效果一點也不連續。最後決定去看看swiper是怎麼實現的。swiper的作法就是把第一張複製一份放到最後面,把最後一張複製一份插到最前面。 以下圖所示:

  

第一張和第四張都被複制了一份。對應的代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn.createLoopItems =  function (){
         var  lastItem =  this .slides[ this .lastIndex];
         var  firstItem =  this .slides[ this .firstIndex];
         var  prevItem = lastItem.cloneNode( true );
         var  nextItem = firstItem.cloneNode( true );
         var  sliderCount =  this .sliderCount+2;
         var  slideWidth =  this .slideWidth;
         this .slideStack.push( this .firstIndex);
         this .slideStack.unshift( this .lastIndex);
         this .wrap.insertBefore(prevItem,firstItem);
         this .wrap.appendChild(nextItem);
         this .wrap.style.width = slideWidth * sliderCount +  'px' ;
         translate3d( this .wrap,slideWidth);
         this .activeIndex += 1;
         this .sliderCount = sliderCount;
         this .lastIndex += 2;
     }

不得不認可這個作法很巧妙。隨便咱們往哪一個方向翻,都不至於出現空白期。當翻到最未尾(數字4)的時候,還能夠再翻一頁,即第一張的複製品,雖然不是真的第一張,可是看起來就像是平滑的過渡到了第一張同樣。不過這是臨時的,咱們須要在過渡完以後,當即回到真正的1的位置上去。由於咱們實際上在未端只補了一張,翻完這一頁,若是不進一步處理,仍是會到頭。這時,就是問題的關鍵了。當咱們往右翻,從第四張翻到複製的第一張時,須要悄悄地,人不知,鬼不覺的把紅框的位置移到1的真身上來。同時把activeIndex也置爲圖1的索引。那麼問題又來了,怎麼才能作到人不知鬼不覺的暗渡陳倉呢?其實很簡單,只要把移位動畫的時間改爲0就能夠了。關鍵代碼以下:

1
transition( this .wrap,0);

不過這一步要在從4變爲1,剛停下來的時候,當即執行。作早了,就會感受是直接從4跳到1,沒有動畫效果,作晚了,就會出現空白,並由於索引溢出而報錯。因此這裏須要一個修復方法:

1
2
3
4
5
6
fn.fixedPrevLoop =  function (){
         var  that =  this ;
         setTimeout( function (){
             that.fixedLoop(that.lastIndex-1)
         },that.params.speed);
     }

  或者:

1
this .container.addEventListener( 'transitionend' , function (){<br>      //監聽動畫結速以後再執行判斷是否要修復<br>},false);

作完這一步,就看起來有連續滾動的效果了,在這個基礎上實現自動輪播就好辦了,只要用定時器,每隔一段時間就執行一下自身就能夠了。代碼以下:

1
2
3
4
5
6
7
8
9
10
11
fn.autoPlay =  function (){
         var  that =  this ;
         if (! this .params.autoplay){
             return ;
         }
         this .timeId = setTimeout( function (){
             that.next();
             //that.prev();
             that.autoPlay();
         }, this .params.delay);
     }

  我註釋掉了prev(), 默認都是向右自動輪播。若是要改爲是往左輪播,只要在這裏加一個一個配置選擇就行了。自動循環都作好了,在此基礎上點擊翻頁,也是很容易的事情了,給按鈕邦定一個click事件,若是是右邊的,就調用next()方法,反之則調用prev()方法。不過我這裏沒有這樣作,由於考慮到後面咱們還要作手勢(鼠標)拖動翻頁效果,我決定用事件代理來作。讓事件通通都冒泡到包裝容器上去處理,這也是提高性能的經常使用技巧之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
fn.bindEvents  =  function (){
         if (Device.desktop){
             this .container.addEventListener( 'mousedown' , this , false );
             this .container.addEventListener( 'mousemove' , this , false );
             document.addEventListener( 'mouseup' , this , false );
         } else {
             this .container.addEventListener( 'touchstart' , this , false );
             this .container.addEventListener( 'touchmove' , this , false );
             document.addEventListener( 'touchend' , this , false );
         }
         this .container.addEventListener( 'transitionend' , this , false );
         this .container.addEventListener( 'click' , this , false );
     }

  爲何這裏的addEventListener爲何是邦定this而不是一個函數呢?簡單說,是由於上下文中有一個handleEvent方法,能夠被監聽函數自動捕獲到,這個函數名是固定的,不明白的能夠自行搜索這個函數名。

1
2
fn.handleEvent =  function (e){
         var  type = e.type;<br>   //注意這裏邊的this<br>}

這樣作的好處是能夠維持事件邦定的那個函數的上下文。簡單說就是不用操心this的指向會變。

作完這一步,就能夠作拖動翻頁了。在pc上用鼠標,在手機上用手指,處理的方式都是同樣的,監聽按下,移動,釋放這三個事件。按下的時候,記住初始座標,移動的時候和這個座標進行對比,計算出移動的距離,而後更新到移動的對象上(紅框)。這裏邊有幾個地方須要注意:

1. 若是移動的時候,不是直線,x座標和y座標都有改變,是判斷成水平拖動仍是垂直拖動?

2. 在pc上,如何判斷是拖動,拖出屏幕外了怎麼處理?

3. 反彈怎麼作?

對於第1點,能夠比較兩個方向距離的大小,誰大聽誰的。若是指向了是水平滾動,那麼能夠直接忽略豎直方向的變化。

對於第2點,能夠把監聽mouseup放到document上去,最好加一個移動的距離大小判斷,若是超過容器的大小,就看成是釋放了,該反彈的反彈,該滑頁的滑頁。

對於第3點,在拖動釋放的時候,判斷移動距離,好比拖動的距離小於屏寬的1/3,就反方向translate相應的距離回去,甚至都不用關心這個距離,反正這時的activeIndex沒有更新的,直接回到這個activeIndex對應的頁就算是反彈了。代碼就是這樣:

1
2
3
4
5
fn.stop =  function (){
         this .axis.x = 0;
         translate3d( this .wrap, this .slideWidth* this .activeIndex);
         transition( this .wrap, this .params.speed);
}

接下來就是作頁碼指示器了,這個簡單,翻頁成功以後就更新一下對應的小點就是了。因爲咱們人爲的插了兩個頁面進去,索引數和頁碼數就對應不起來了,實際參與滾動的圖片有6張,可是隻能顯示4個點。我作的時候走了一些彎路,如今總結起來無非就是兩點:

1. 給小圓點加一個屬性用來標記是哪一個頁面。用於處理點擊滾動的時候,知道是跳到哪一個頁面。

2. 用一個數組來保存頁面索引,好比【3,0,1,2,3,1】,這樣當自動或拖動翻頁的時候,能夠經過activeIndex的值,肯定要高亮哪一個頁碼指示器。(小圓點)

也可能還有更好的方法,暫時就先這樣實現吧。先把功能作出來,後面有時間,有靈感了再去優化。

到這裏,幾本上就作完了,只是還要再完善一些邊際狀況,好比一張圖都沒有的狀況,默認參數的處理等。

思考

除了這個方法以外是否是有其它解決方法呢?好比下圖這樣,紅框中只放三張,多餘的疊在屏後面,移動的時候不是移紅框,而是真實的移動圖片?

 

 這種方法也是能夠行的通的,不過我在嘗試的時候,發現這種方法在手機上有些卡頓,在電腦上看,容器邊框會有閃動,緣由沒有深刻去查了。

  咳!咳..,下載源碼請上號稱全球最大的同性交友網站github.com   , 在線預覽無圖片版本

小結一下:

寫到這裏的時候,主體的邏輯差很少就實現了, 只用了大約三百多行代碼,雖然很精簡,可是這裏還有許多東西沒有考慮進去,好比豎直方向的滾動,兼容性問題等等。經過畫草圖的方法來幫助理清思路,遇到困難,能夠借鑑別人的實現方法,參考但不是原封不動的複製粘貼。代碼組織要考慮擴展性和可讀性,先從程序的骨架寫起,而後再去寫方法,處理細節問題。經過動手實踐,能夠發現一些看似簡單的東西,作起來也不是那麼容易的。本身作出來以後,再去看別人寫的好的代碼,就會知道人家哪些地方比我實現的好,有哪些值得學習的地方。

 

 

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<title>輪播</title>
		<style type="text/css">
			body {
				padding: 0;
				min-width: 300px;
				max-width: 640px;
				margin: 0 auto;
			}
			
			ul {
				list-style: none;
			}
			
			ul,
			li {
				margin: 0;
				padding: 0;
			}
			
			.slider-wrapper {
				position: relative;
				width: 100%;
				height: 220px;
				overflow: hidden;
				background-color: pink;
			}
			
			.slider-items {
				position: relative;
				height: 100%;
				 
			}
			
			.slider-item:nth-child(odd) {
				background-color: red;
			}
			
			.slider-item:nth-child(even) {
				background-color: green;
			}
			
			.slider-item {
				float: left;
				height: 320px;
				line-height: 320px;
				text-align: center;
			}
			
			.slider-item>img {
				width: 100%;
				-webkit-user-select: none;
				-ms-user-select: none;
				user-select: none;
				pointer-events: none;
			}
			
			.slider-pagination {
				position: absolute;
				bottom: 10px;
				left: 0;
				width: 100%;
				text-align: center;
				-webkit-transition-duration: .3s;
				-moz-transition-duration: .3s;
				-o-transition-duration: .3s;
				transition-duration: .3s;
			}
			
			.slider-bullet {
				width: 8px;
				height: 8px;
				margin: 0 5px;
				display: inline-block;
				border-radius: 100%;
				background-color: black;
				opacity: .2;
				cursor: pointer;
			}
			
			.slider-bullet-active {
				opacity: 1;
				background-color: #007aff;
			}
			
			.slider-button {
				position: absolute;
				top: 50%;
				width: 50px;
				height: 50px;
				text-align: center;
				line-height: 50px;
				margin-top: -25px;
				z-index: 10;
				font-size: 4rem;
				color: gray;
				-webkit-user-select: none;
				user-select: none;
			}
			
			.next {
				right: 0px;
			}
			
			.prev {
				left: 0px;
			}
		</style>
	</head>

	<body>
		<div id="slider" class="slider-wrapper">
			<ul class="slider-items">
				<li class="slider-item">1</li>
				<li class="slider-item">2</li>
				<li class="slider-item">3</li>
				<li class="slider-item">4</li>
			</ul>
		</div>
		<script>
			window.onload = function() {
				Slider('#slider')
			}
		</script>
		<script type="text/javascript">
			;
			(function(global, factory) {

				"use strict";

				if(typeof module === "object" && typeof module.exports === "object") {
					module.exports = global.document ?
						factory(global, true) :
						function(w) {
							if(!w.document) {
								throw new Error("Slider requires a window with a document");
							}
							return factory(w);
						};
				} else {
					factory(global);
				}

				// Pass this if window is not defined yet
			})(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
				"use strict";

				var version = '1.0.0';
				var defaults = {
					speed: 500,
					delay: 5000,
					direction: 'horizontal',
					autoplay: true,
					bounceRatio: 0.5,
					pagination: true,
					loop: true,
					buttons: true,
					paginationClass: 'slider-pagination',
					bulletClass: 'slider-bullet',
					bulletActiveClass: 'slider-bullet-active'
				};

				var isObject = function(obj) {
					return Object.prototype.toString.call(obj) === "[object Object]";
				}

				var extend = function(target, source) {
					if(!isObject(source)) {
						source = {};
					}
					for(var i in target) {
						if(source[i] === undefined) {
							source[i] = target[i]
						}
					}
					return source;
				}
				var Device = (function() {
					var ua = navigator.userAgent;
					var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
					var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
					var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
					var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
					return {
						ios: ipad || iphone || ipod,
						android: android,
						desktop: !(ipad || iphone || ipod || android)
					};
				})();

				function translate3d(element, x, y) {
					x = x === undefined ? 0 : x;
					y = y === undefined ? 0 : x;
					element.style['-webkit-transform'] = 'translate3d(-' + x + 'px,' + y + 'px,0px)';
					element.style['transform'] = 'translate3d(-' + x + 'px,' + y + 'px,0px)';
				}

				function transition(element, time) {
					element.style['-webkit-transition-duration'] = time + 'ms';
					element.style['transition-duration'] = time + 'ms';
				}

				function Slider(selector, options) {
					options = extend(defaults, options);
					return new Slider.init(selector, options);
				}

				Slider.init = function(selector, params) {
					var container = document.querySelector(selector);
					var wrap = container.children[0];
					var slides = wrap.children;
					var sliderCount = slides.length;
					if(sliderCount === 0) {
						console.warn('Slider children require at least one');
						return this;
					}
					this.container = container;
					this.wrap = wrap;
					this.slides = slides;
					this.params = {};
					extend(params, this.params);
					this.sliderCount = sliderCount;
					this.lastIndex = sliderCount - 1;
					this.firstIndex = 0;
					this.isAnimating = false;
					this.axis = {
						x: 0,
						y: 0
					};
					this.initSlides();
					this.bindEvents();
				}

				var fn = Slider.init.prototype;

				fn.initSlides = function() {
					var width = this.wrap.clientWidth;
					this.slideWidth = width;
					this.wrap.style.width = width * this.sliderCount + 'px';
					this.bounceWidth = this.params.bounceRatio * width;
					this.activeIndex = 0;
					this.slideStack = [];
					for(var i = 0; i < this.sliderCount; i++) {
						this.slides[i].style.width = width + 'px';
						this.slideStack.push(i);
					}

					if(this.params.pagination) {
						this.createPagination();
					}

					if(this.params.loop) {
						this.createLoopItems();
					}

					if(this.params.buttons) {
						this.createButtons();
					}

					if(this.params.autoplay) {
						this.autoPlay();
					}
				}

				fn.createLoopItems = function() {
					var lastItem = this.slides[this.lastIndex];
					var firstItem = this.slides[this.firstIndex];
					var prevItem = lastItem.cloneNode(true);
					var nextItem = firstItem.cloneNode(true);
					var sliderCount = this.sliderCount + 2;
					var slideWidth = this.slideWidth;
					this.slideStack.push(this.firstIndex);
					this.slideStack.unshift(this.lastIndex);
					this.wrap.insertBefore(prevItem, firstItem);
					this.wrap.appendChild(nextItem);
					this.wrap.style.width = slideWidth * sliderCount + 'px';
					translate3d(this.wrap, slideWidth);
					this.activeIndex += 1;
					this.sliderCount = sliderCount;
					this.lastIndex += 2;
				}

				fn.fixedLoop = function(activeIndex) {
					if(!this.params.loop) return;
					translate3d(this.wrap, this.slideWidth * activeIndex);
					transition(this.wrap, 0);
					this.activeIndex = activeIndex;
					this.isAnimating = false;
				}

				fn.fixedNextLoop = function() {
					var that = this;
					setTimeout(function() {
						that.fixedLoop(1)
					}, that.params.speed);
				}

				fn.fixedPrevLoop = function() {
					var that = this;
					setTimeout(function() {
						that.fixedLoop(that.lastIndex - 1)
					}, that.params.speed);
				}

				fn.createPagination = function() {
					var ul = document.createElement('ul');
					var bullets = [];
					var bulletClass = this.params.bulletClass;
					ul.className = this.params.paginationClass;
					for(var i = 0; i < this.sliderCount; i++) {
						var li = document.createElement('li');
						li.className = bulletClass;
						ul.appendChild(li);
						bullets.push(li);
					}
					this.container.appendChild(ul);
					this.bullets = bullets;
					this.setActivePagination();
				}

				fn.createButtons = function() {
					var prev = document.createElement('div');
					var next = document.createElement('div');
					prev.className = 'slider-button prev';
					next.className = 'slider-button next';
					prev.innerHTML = '<';
					next.innerHTML = '>';
					this.container.appendChild(prev);
					this.container.appendChild(next);
				}

				fn.setActivePagination = function() {
					var prevIndex = this.activeBulletIndex;
					var activeIndex = this.activeIndex;
					activeIndex = this.slideStack[activeIndex];
					if(prevIndex === activeIndex) {
						return;
					}
					if(prevIndex !== undefined) {
						this.bullets[prevIndex].className = this.params.bulletClass;
					}
					this.bullets[activeIndex].className += ' ' + this.params.bulletActiveClass;
					this.activeBulletIndex = activeIndex;
				}

				fn.autoPlay = function() {
					var that = this;
					if(!this.params.autoplay) {
						return;
					}
					this.timeId = setTimeout(function() {
						that.next();
						//that.prev();
						that.autoPlay();
					}, this.params.delay);
				}

				fn.next = function() {
					var activeIndex = ++this.activeIndex;
					if(activeIndex > this.lastIndex) {
						this.params.autoplay && clearTimeout(this.timeId);
						return;
					}
					this.isAnimating = true;
					translate3d(this.wrap, activeIndex * this.slideWidth);
					transition(this.wrap, this.params.speed);
					this.setActivePagination();
					if(activeIndex === this.lastIndex) {
						this.fixedNextLoop();
					}
				}

				fn.prev = function() {
					var activeIndex = --this.activeIndex;
					if(activeIndex < this.firstIndex) {
						this.params.autoplay && clearTimeout(this.timeId);
						return;
					}
					this.isAnimating = true;
					translate3d(this.wrap, activeIndex * this.slideWidth);
					transition(this.wrap, this.params.speed);
					this.setActivePagination();
					if(activeIndex === this.firstIndex) {
						this.fixedPrevLoop();
					}
				}

				fn.bindEvents = function() {
					if(Device.desktop) {
						this.container.addEventListener('mousedown', this, false);
						this.container.addEventListener('mousemove', this, false);
						document.addEventListener('mouseup', this, false);
					} else {
						this.container.addEventListener('touchstart', this, false);
						this.container.addEventListener('touchmove', this, false);
						document.addEventListener('touchend', this, false);
					}
					this.container.addEventListener('transitionend', this, false);
					this.container.addEventListener('click', this, false);
				}

				fn.transitionend = function() {
					this.isAnimating = false;
				}

				fn.start = function(pageX) {
					this.axis.x = parseInt(pageX);
					if(this.params.autoplay) {
						this.params.autoplay = false;
						this.timeId && clearTimeout(this.timeId);
					}
				}

				fn.move = function(pageX) {
					pageX = parseInt(pageX);
					if(this.isAnimating) return;
					if(this.axis.x === 0) return;
					if(pageX > this.slideWidth || pageX < 0) {
						return;
					}
					var distance = this.axis.x - pageX;
					translate3d(this.wrap, distance + this.slideWidth * this.activeIndex);
					transition(this.wrap, 0);
					if(distance > 0) {
						if(distance > this.bounceWidth) {
							this.next();
							this.axis.x = 0;
						}
					} else {
						if(-distance > this.bounceWidth) {
							this.prev();
							this.axis.x = 0;
						}
					}
				}

				fn.stop = function() {
					if(this.isAnimating) return;
					this.axis.x = 0;
					translate3d(this.wrap, this.slideWidth * this.activeIndex);
					transition(this.wrap, this.params.speed);
				}

				fn.handleEvent = function(e) {
					var type = e.type;
					switch(type) {
						case 'mousedown':
							this.start(e.pageX);
							break;
						case 'mousemove':
							this.move(e.pageX);
							break;
						case 'mouseup':
							this.stop();
							break;
						case 'touchstart':
							this.start(e.targetTouches[0].pageX);
							break;
						case 'touchmove':
							this.move(e.targetTouches[0].pageX);
							break;
						case 'touchend':
							this.stop();
							break;
						case 'transitionend':
						case 'WebkitTransitionend':
							this.transitionend();
							break;
						case 'click':
							e.stopPropagation();
							var evt = e.target.className.split(' ')[1];
							if(evt === 'prev' || evt === 'next') {
								this[evt]();
							}
							break;
						default:
							break;
					}
				}

				if(!noGlobal) {
					window.Slider = Slider;
				}
				return Slider;
			});
		</script>
	</body>

</html>
相關文章
相關標籤/搜索