【iScroll源碼學習02】分解iScroll三個核心事件點

前言

最近兩天看到不少的總結性發言,我想一想今年好像個人變化挺大的,是否是該晚上來水一發呢?嗯,決定了,晚上來水一發!css

上週六,咱們簡單模擬了下iScroll的實現,週日咱們開始了學習iScroll的源碼,今天咱們接着上次的記錄學習,由於最近事情稍微有點多了html

學習進度可能要放慢,並且iScroll這個庫實際意義很大,不能囫圇吞棗的學習,要學到精華,而且要用於項目中的,因此初步規劃是最近兩週主要圍繞iScroll展開android

然後兩個選擇:① 分離iScroll代碼用於項目;② 抄襲iScroll精華部分用於項目。不管如何都要用於項目......web

幾個事件點

iScroll的總體邏輯由三大事件點組成:數組

① touchStart(mousedown)瀏覽器

② touchMove(mousemove)app

③ touchEnd(mouseUp)less

也就是iScroll總體的功能邏輯實際上是由這幾個事件串起來的,其中dom

touchStart會保留一些初始化操做,或者中止正在進行的動畫ide

touchMove會帶動dom一塊兒移動

而touchEnd最爲複雜,在touchend階段可能須要處理不少東西

① 通常性拖動結束事件
② 超出邊界還原後觸發的事件(此時能夠滾動加載數據)
③ 若是這次爲一次按鈕點擊,須要觸發按鈕事件那麼還有對preventDefault進行處理(preventDefault可能致使事件不觸發)
④ 若是這次爲一次點擊事件,而且對象爲文本框或者select(其它會得到焦點的事件),那麼應該讓其得到焦點,而且彈出鍵盤
⑤ ......

以上爲主觀臆測下的猜測,咱們來看看iScroll實際幹了些什麼,下面再細細的分析各個階段

start

 1 _start: function (e) {
 2   // React to left mouse button only
 3   if (utils.eventType[e.type] != 1) {
 4     if (e.button !== 0) {
 5       return;
 6     }
 7   }
 8   if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) {
 9     return;
10   }
11   if (this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
12     e.preventDefault();
13   }
14   var point = e.touches ? e.touches[0] : e,
15 pos;
16 
17   this.initiated = utils.eventType[e.type];
18   this.moved = false;
19   this.distX = 0;
20   this.distY = 0;
21   this.directionX = 0;
22   this.directionY = 0;
23   this.directionLocked = 0;
24 
25   this._transitionTime();
26 
27   this.startTime = utils.getTime();
28 
29   if (this.options.useTransition && this.isInTransition) {
30     this.isInTransition = false;
31     pos = this.getComputedPosition();
32     this._translate(Math.round(pos.x), Math.round(pos.y));
33     this._execEvent('scrollEnd');
34   } else if (!this.options.useTransition && this.isAnimating) {
35     this.isAnimating = false;
36     this._execEvent('scrollEnd');
37   }
38 
39   this.startX = this.x;
40   this.startY = this.y;
41   this.absStartX = this.x;
42   this.absStartY = this.y;
43   this.pointX = point.pageX;
44   this.pointY = point.pageY;
45 
46   this._execEvent('beforeScrollStart');
47 },
View Code
1 if ( utils.eventType[e.type] != 1 ) {
2     if ( e.button !== 0 ) {
3         return;
4     }
5 }

首先一段代碼特別針對非touch事件進行了處理,其中的意圖暫時不明,應該是隻有點擊鼠標左鍵的狀況下才會觸發下面邏輯

1 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
2     return;
3 }

第二段代碼作了一次是否開始的驗證,this.enabled應該是程序功能總開關,this.initiated爲首次觸發touchStart的事件類型

多是mousedown,touchstart或者其餘,若是兩次不等的話,這裏也會終止流程(此段代碼確實不明意圖)

// This should find all Android browsers lower than build 535.19 (both stock browser and webview)
me.isBadAndroid = /Android/.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion));
1 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
2     e.preventDefault();
3 }

第三段作了一些兼容性操做,各位能夠看到只有這裏有preventDefault的操做,若是默寫dom元素在你手觸碰會有默認的事件,好比文本框,便會觸發

可是咱們默認是阻止的,而在一些android設備上市必須阻止的,這裏建議都阻止

 1 var point = e.touches ? e.touches[0] : e,
 2 pos;
 3 
 4 this.initiated = utils.eventType[e.type];
 5 this.moved = false;
 6 this.distX = 0;
 7 this.distY = 0;
 8 this.directionX = 0;
 9 this.directionY = 0;
10 this.directionLocked = 0;

接下來進行了一些初始化屬性的定義,其中比較重要的是

① point作了最簡單的兼容性處理

② this.moved你想知道如今控件是否是在拖動就看他了

而後這裏執行了一個方法:_transitionTime

 1 _transitionTime: function (time) {
 2   time = time || 0;
 3 
 4   this.scrollerStyle[utils.style.transitionDuration] = time + 'ms';
 5 
 6   if (!time && utils.isBadAndroid) {
 7     this.scrollerStyle[utils.style.transitionDuration] = '0.001s';
 8   }
 9 
10   if (this.indicators) {
11     for (var i = this.indicators.length; i--; ) {
12       this.indicators[i].transitionTime(time);
13     }
14   }
15 
16   // INSERT POINT: _transitionTime
17 },

utils具備如下style屬性:

1 me.extend(me.style = {}, {
2     transform: _transform,
3     transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
4     transitionDuration: _prefixStyle('transitionDuration'),
5     transitionDelay: _prefixStyle('transitionDelay'),
6     transformOrigin: _prefixStyle('transformOrigin')
7 });

這裏爲其設置了適合放棄瀏覽器的運動時間屬性,就是簡單的兼容處理

在有些android瀏覽器上,這個使用是有問題的,因此就直接當沒傳時間,直接給了個0.001s

其中的indicators就是咱們的滾動條,這裏既然涉及到了,咱們也暫時無論,由於涉及到滾動條的篇幅也不小,咱們暫時不關注

這個方法也涉及滾動條相關,咱們這裏先簡單提一下,後面在補充,如今繼續看下面的邏輯

 

再下面就開始真正初始化信息,這些信息在如下會被用到

 1 this.startTime = utils.getTime();
 2 
 3 if ( this.options.useTransition && this.isInTransition ) {
 4     this.isInTransition = false;
 5     pos = this.getComputedPosition();
 6     this._translate(Math.round(pos.x), Math.round(pos.y));
 7     this._execEvent('scrollEnd');
 8 } else if ( !this.options.useTransition && this.isAnimating ) {
 9     this.isAnimating = false;
10     this._execEvent('scrollEnd');
11 }
12 
13 this.startX    = this.x;
14 this.startY    = this.y;
15 this.absStartX = this.x;
16 this.absStartY = this.y;
17 this.pointX    = point.pageX;
18 this.pointY    = point.pageY;

首先記錄了手指觸屏屏幕的時間,然後記錄手指所處的位置,其中有兩個if語句須要咱們注意,這裏的代碼仍是至關關鍵的

這段話的意義是告訴咱們,若是咱們當前正在運動,而此時觸屏了,那麼就觸發scrollEnd事件中止動畫(這裏很是關鍵)

其中如果使用了CSS3的屬性實現動畫會作一些特別的處理,這裏的this.isAnimating = false 是一個關鍵點,各位要注意

他在首次爲undefined(我以爲這種屬性應該給他一個初始化值false),運動過程當中爲true,運動結束爲false

這裏再提一下如果使用CSS3的話,會立刻讓dom移動到特定位置,而後中止動畫

 1 _translate: function (x, y) {
 2     if ( this.options.useTransform ) {
 3         this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
 4 
 5     } else {
 6         x = Math.round(x);
 7         y = Math.round(y);
 8         this.scrollerStyle.left = x + 'px';
 9         this.scrollerStyle.top = y + 'px';
10     }
11     this.x = x;
12     this.y = y;
13 if ( this.indicators ) {
14     for ( var i = this.indicators.length; i--; ) {
15         this.indicators[i].updatePosition();
16     }
17 }
18 // INSERT POINT: _translate
19 },

下面的代碼依舊在操做滾動條,不用如今關注,這裏將信息所有寫入了scrollerStyle對象,同事dom style屬性的引用,這裏就直接給賦值了

然咱們來看看this._execEvent('scrollEnd');這段代碼

首先_execEvent是用於觸發存儲在this._event數組中的事件的方法,而後咱們只看scrollEnd便可,這裏的事件機制,咱們提到後面來講

很奇怪的是,這裏有觸發事件的代碼卻沒有註冊的代碼,這是由於這個接口應該是開放給用戶的,而後這裏的beforeScrollStart也是開放給用戶註冊事件的

到此touchstart相關事件就結束了,咱們接下來看move事件

move

 1 _move: function (e) {
 2   if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
 3     return;
 4   }
 5 
 6   if (this.options.preventDefault) {    // increases performance on Android? TODO: check!
 7     e.preventDefault();
 8   }
 9 
10   var point = e.touches ? e.touches[0] : e,
11     deltaX = point.pageX - this.pointX,
12     deltaY = point.pageY - this.pointY,
13     timestamp = utils.getTime(),
14     newX, newY,
15     absDistX, absDistY;
16 
17   this.pointX = point.pageX;
18   this.pointY = point.pageY;
19 
20   this.distX += deltaX;
21   this.distY += deltaY;
22   absDistX = Math.abs(this.distX);
23   absDistY = Math.abs(this.distY);
24 
25   // We need to move at least 10 pixels for the scrolling to initiate
26   if (timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10)) {
27     return;
28   }
29 
30   // If you are scrolling in one direction lock the other
31   if (!this.directionLocked && !this.options.freeScroll) {
32     if (absDistX > absDistY + this.options.directionLockThreshold) {
33       this.directionLocked = 'h';     // lock horizontally
34     } else if (absDistY >= absDistX + this.options.directionLockThreshold) {
35       this.directionLocked = 'v';     // lock vertically
36     } else {
37       this.directionLocked = 'n';     // no lock
38     }
39   }
40 
41   if (this.directionLocked == 'h') {
42     if (this.options.eventPassthrough == 'vertical') {
43       e.preventDefault();
44     } else if (this.options.eventPassthrough == 'horizontal') {
45       this.initiated = false;
46       return;
47     }
48 
49     deltaY = 0;
50   } else if (this.directionLocked == 'v') {
51     if (this.options.eventPassthrough == 'horizontal') {
52       e.preventDefault();
53     } else if (this.options.eventPassthrough == 'vertical') {
54       this.initiated = false;
55       return;
56     }
57 
58     deltaX = 0;
59   }
60 
61   deltaX = this.hasHorizontalScroll ? deltaX : 0;
62   deltaY = this.hasVerticalScroll ? deltaY : 0;
63 
64   newX = this.x + deltaX;
65   newY = this.y + deltaY;
66 
67   // Slow down if outside of the boundaries
68   if (newX > 0 || newX < this.maxScrollX) {
69     newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
70   }
71   if (newY > 0 || newY < this.maxScrollY) {
72     newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
73   }
74 
75   this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
76   this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
77 
78   if (!this.moved) {
79     this._execEvent('scrollStart');
80   }
81 
82   this.moved = true;
83 
84   this._translate(newX, newY);
85 
86   /* REPLACE START: _move */
87 
88   if (timestamp - this.startTime > 300) {
89     this.startTime = timestamp;
90     this.startX = this.x;
91     this.startY = this.y;
92   }
93 
94   /* REPLACE END: _move */
95 
96 },
View Code

move爲功能第二個階段,首先仍然是作全局開關檢測,若是不經過就直接給幹掉

1 if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
2   return;
3 }
4 
5 if (this.options.preventDefault) {    // increases performance on Android? TODO: check!
6   e.preventDefault();
7 }

而後這個時候必需要將瀏覽器默認事件搞掉,不然你滾動時候,若是body跟着一塊兒滾動就麻煩了

PS:Android下有些瀏覽器preventDefault並不能阻止瀏覽器滾動,這事情很煩

接下來就是記錄當前移動數據,爲dom移動作準備了:

 1 var point = e.touches ? e.touches[0] : e,
 2 deltaX = point.pageX - this.pointX,
 3 deltaY = point.pageY - this.pointY,
 4 timestamp = utils.getTime(),
 5 newX, newY,
 6 absDistX, absDistY;
 7 
 8 this.pointX = point.pageX;
 9 this.pointY = point.pageY;
10 
11 this.distX += deltaX;
12 this.distY += deltaY;
13 absDistX = Math.abs(this.distX);
14 absDistY = Math.abs(this.distY);

首先記錄了當前鼠標位置,然後記錄移動位置後,重置當前鼠標位置,而後這裏作了一個判斷,這個判斷是若是咱們手指一直停到一個位置不動的話,就給他終止了

這裏也作了一個優化,爲了防止瀏覽器不停的重繪嗎,必定是移動10px以上才真正的移動

1 if (!this.directionLocked && !this.options.freeScroll) {
2   if (absDistX > absDistY + this.options.directionLockThreshold) {
3     this.directionLocked = 'h';     // lock horizontally
4   } else if (absDistY >= absDistX + this.options.directionLockThreshold) {
5     this.directionLocked = 'v';     // lock vertically
6   } else {
7     this.directionLocked = 'n';     // no lock
8   }
9 }

這裏作了一個判斷,讓DOM朝一個方向運動便可,由於咱們關注的是Y方向,這裏能夠暫時不予關注

而後開始計算新位置了,這裏要開始移動了哦(注意:這裏作了一個判斷若是超出邊界的話,拖動率要減低

 1 newX = this.x + deltaX;
 2 newY = this.y + deltaY;
 3 
 4 // Slow down if outside of the boundaries
 5 if (newX > 0 || newX < this.maxScrollX) {
 6   newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
 7 }
 8 if (newY > 0 || newY < this.maxScrollY) {
 9   newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
10 }

咱們在touchstart時候將this.moved設置爲了false,這裏就觸發一個scrollSatrt事件後將其還原爲true,因此這個事件只會觸發一次,

這個事件一樣是開放給用戶的,iScroll自己並未註冊任何事件

1 if (timestamp - this.startTime > 300) {
2   this.startTime = timestamp;
3   this.startX = this.x;
4   this.startY = this.y;
5 }

每300ms會重置一次當前位置以及開始時間,這個就是爲何咱們在抓住不放好久忽然丟開仍然有長距離移動的緣由,這個比較精妙哦!

最後咱們說下其中的_translate方法,這個方法用於移動DOM,這種封裝的思想很不錯的,值得借鑑,如今就進入關鍵點了touchend

end

 1 _end: function (e) {
 2   if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
 3     return;
 4   }
 5 
 6   if (this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
 7     e.preventDefault();
 8   }
 9 
10   var point = e.changedTouches ? e.changedTouches[0] : e,
11     momentumX,
12     momentumY,
13     duration = utils.getTime() - this.startTime,
14     newX = Math.round(this.x),
15     newY = Math.round(this.y),
16     distanceX = Math.abs(newX - this.startX),
17     distanceY = Math.abs(newY - this.startY),
18     time = 0,
19     easing = '';
20 
21   this.isInTransition = 0;
22   this.initiated = 0;
23   this.endTime = utils.getTime();
24 
25   // reset if we are outside of the boundaries
26   if (this.resetPosition(this.options.bounceTime)) {
27     return;
28   }
29 
30   this.scrollTo(newX, newY); // ensures that the last position is rounded
31 
32   // we scrolled less than 10 pixels
33   if (!this.moved) {
34     if (this.options.tap) {
35       utils.tap(e, this.options.tap);
36     }
37 
38     if (this.options.click) {
39       utils.click(e);
40     }
41 
42     this._execEvent('scrollCancel');
43     return;
44   }
45 
46   if (this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100) {
47     this._execEvent('flick');
48     return;
49   }
50 
51   // start momentum animation if needed
52   if (this.options.momentum && duration < 300) {
53     momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0) : { destination: newX, duration: 0 };
54     momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0) : { destination: newY, duration: 0 };
55     newX = momentumX.destination;
56     newY = momentumY.destination;
57     time = Math.max(momentumX.duration, momentumY.duration);
58     this.isInTransition = 1;
59   }
60 
61 
62   if (this.options.snap) {
63     var snap = this._nearestSnap(newX, newY);
64     this.currentPage = snap;
65     time = this.options.snapSpeed || Math.max(
66             Math.max(
67                 Math.min(Math.abs(newX - snap.x), 1000),
68                 Math.min(Math.abs(newY - snap.y), 1000)
69             ), 300);
70     newX = snap.x;
71     newY = snap.y;
72 
73     this.directionX = 0;
74     this.directionY = 0;
75     easing = this.options.bounceEasing;
76   }
77 
78   // INSERT POINT: _end
79 
80   if (newX != this.x || newY != this.y) {
81     // change easing function when scroller goes out of the boundaries
82     if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY) {
83       easing = utils.ease.quadratic;
84     }
85 
86     this.scrollTo(newX, newY, time, easing);
87     return;
88   }
89 
90   this._execEvent('scrollEnd');
91 },
View Code

開始咱們就說過,touchend爲這個控件一個關鍵點與難點,如今咱們就來啃一啃,這個看完了,iScroll核心部分也就結束了,後面就只須要拆解分析便可

首先仍然是一點初始化操做

1 if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
2   return;
3 }
4 
5 if (this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
6   e.preventDefault();
7 }

然後逐步好戲上場了,在手指離開前作了狀態保存

 1 var point = e.changedTouches ? e.changedTouches[0] : e,
 2 momentumX,
 3 momentumY,
 4 duration = utils.getTime() - this.startTime,
 5 newX = Math.round(this.x),
 6 newY = Math.round(this.y),
 7 distanceX = Math.abs(newX - this.startX),
 8 distanceY = Math.abs(newY - this.startY),
 9 time = 0,
10 easing = '';
11 
12 this.isInTransition = 0;
13 this.initiated = 0;
14 this.endTime = utils.getTime();

duration是當前拖動的事件,這裏可不是手指觸屏到離開哦,由於move時候每300ms變了一次

PS:這裏想象一下若是咱們想要快速的滑動是否是觸屏屏幕很快呢,而咱們一直拖動DOM在最後也是有可能想讓他快速移動的

記錄當前x,y位置記錄當前移動位置distanceY,而後重置結束時間,這裏有一個resetPosition方法:

 1 resetPosition: function (time) {
 2     var x = this.x,
 3         y = this.y;
 4 
 5     time = time || 0;
 6 
 7     if ( !this.hasHorizontalScroll || this.x > 0 ) {
 8         x = 0;
 9     } else if ( this.x < this.maxScrollX ) {
10         x = this.maxScrollX;
11     }
12 
13     if ( !this.hasVerticalScroll || this.y > 0 ) {
14         y = 0;
15     } else if ( this.y < this.maxScrollY ) {
16         y = this.maxScrollY;
17     }
18 
19     if ( x == this.x && y == this.y ) {
20         return false;
21     }
22 
23     this.scrollTo(x, y, time, this.options.bounceEasing);
24 
25     return true;
26 },

他是記錄咱們是否是已經離開了邊界了,若是離開邊界了就不會執行後面邏輯,而直接重置DOM位置,這裏還用到了咱們的scrollTo方法,該方法尤爲關鍵

scrollTo

 1 scrollTo: function (x, y, time, easing) {
 2     easing = easing || utils.ease.circular;
 3 
 4     this.isInTransition = this.options.useTransition && time > 0;
 5 
 6     if ( !time || (this.options.useTransition && easing.style) ) {
 7         this._transitionTimingFunction(easing.style);
 8         this._transitionTime(time);
 9         this._translate(x, y);
10     } else {
11         this._animate(x, y, time, easing.fn);
12     }
13 },

這個方法是此處一個重要的方法,傳入距離與時間後,他就會高高興興的移動到對應位置

若是啓用了CSS3的動畫,便會使用CSS3動畫方式進行動畫(這個動畫咱們下期再說),不然使用_animate方法(js實現方案)

 1 _animate: function (destX, destY, duration, easingFn) {
 2     var that = this,
 3         startX = this.x,
 4         startY = this.y,
 5         startTime = utils.getTime(),
 6         destTime = startTime + duration;
 7 
 8     function step () {
 9         var now = utils.getTime(),
10             newX, newY,
11             easing;
12 
13         if ( now >= destTime ) {
14             that.isAnimating = false;
15             that._translate(destX, destY);
16 
17             if ( !that.resetPosition(that.options.bounceTime) ) {
18                 that._execEvent('scrollEnd');
19             }
20 
21             return;
22         }
23 
24         now = ( now - startTime ) / duration;
25         easing = easingFn(now);
26         newX = ( destX - startX ) * easing + startX;
27         newY = ( destY - startY ) * easing + startY;
28         that._translate(newX, newY);
29 
30         if ( that.isAnimating ) {
31             rAF(step);
32         }
33     }
34 
35     this.isAnimating = true;
36     step();
37 },

這裏用到了前文說描述的settimeout實現動畫方案,這裏有一點須要咱們回到start部分從新思考,爲何CSS中止了動畫?

緣由是由於transitionend事件

transitionend 事件會在 CSS transition 結束後觸發. 當transition完成前移除transition時,好比移除css的transition-property 屬性,事件將不會被觸發.
 1 _transitionEnd: function (e) {
 2     if ( e.target != this.scroller || !this.isInTransition ) {
 3         return;
 4     }
 5 
 6     this._transitionTime();
 7     if ( !this.resetPosition(this.options.bounceTime) ) {
 8         this.isInTransition = false;
 9         this._execEvent('scrollEnd');
10     }
11 },

因此,咱們第二次touchstart時候,便高高興興中止了動畫(之一_transitionTime未傳time時候會重置時間),因此先取消動畫再移動位置

因而繼續回到咱們的end事件,

1 this.scrollTo(newX, newY);

若是沒有超出邊界便滑動到應該去的位置(這裏有動畫哦)

點擊狀況

固然,咱們手指可能當前只不過想點擊而已,這個時候就要觸發相關的點擊事件了,若是須要獲取焦點,便獲取焦點

PS:他這裏還模擬的fastclick想提高響應速度,可是他這樣會引發大量BUG

 1 if (!this.moved) {
 2   if (this.options.tap) {
 3     utils.tap(e, this.options.tap);
 4   }
 5 
 6   if (this.options.click) {
 7     utils.click(e);
 8   }
 9 
10   this._execEvent('scrollCancel');
11   return;
12 }
13 
14 if (this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100) {
15   this._execEvent('flick');
16   return;
17 }

運動參數

第一步的scrollTo其實能夠放到move裏面去,後面就用到了咱們上文所說,根據動力加速度計算出來的動畫參數:

1 if (this.options.momentum && duration < 300) {
2   momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0) : { destination: newX, duration: 0 };
3   momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0) : { destination: newY, duration: 0 };
4   newX = momentumX.destination;
5   newY = momentumY.destination;
6   time = Math.max(momentumX.duration, momentumY.duration);
7   this.isInTransition = 1;
8 }

那個snap沒必要關注,直接看下面,在此使用

1 this.scrollTo(newX, newY, time, easing);

開始運動,最後觸發scrollend事件,這裏若是超出邊界會執行resetPosition方法還原的,沒必要關心

由此,咱們幾大核心事件點便學習結束了,輕鬆愉快哈

結語

今天學習了iScroll的幾個核心點,咱們下次來講下他的滾動條以及事件機制相關,整個iScroll就七七八八了

相關文章
相關標籤/搜索