摘要:最后調(diào)用函數(shù)來判斷是否需要重置位置保存事件的類型,如果跟已經(jīng)保存的事件類型不是同一類,不繼續(xù)執(zhí)行函數(shù)。如果在滾動狀態(tài),調(diào)用函數(shù)來獲取的位置,調(diào)用方法讓停在當前位置。主要是選擇動畫效果,調(diào)用或是來進行滾動根據(jù)所選的動畫效果,在每一個下調(diào)用函數(shù)
背景
最近開發(fā)移動端項目用到了iscroll,踩了不少坑,因此閱讀源碼加深下對這個工具的了解。
本次閱讀的是iscroll-lite,包含了主要的功能,比完整版少了鼠標滾輪,滾動后對齊到特定位置,按鍵綁定及定制滾動條等功能。
以當前的5.2版本為例,前三百行是工具函數(shù),封裝了一些工具。三百行到四百行是構(gòu)造函數(shù)IScroll,起到配置和初始化的效果。四百行到一千修改了IScroll的原型,給IScroll實例加上了各種方法。最后是模塊化相關(guān)的判斷。總體的結(jié)構(gòu)是很清晰的。
工具函數(shù)用于瀏覽器兼容。
var _vendor = (function () { var vendors = ["t", "webkitT", "MozT", "msT", "OT"], transform, i = 0, l = vendors.length; for ( ; i < l; i++ ) { transform = vendors[i] + "ransform"; if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); } return false; })(); function _prefixStyle (style) { if ( _vendor === false ) return false; if ( _vendor === "" ) return style; return _vendor + style.charAt(0).toUpperCase() + style.substr(1); }
判斷瀏覽器是否支持相關(guān)的特性
me.extend(me, { hasTransform: _transform !== false, hasPerspective: _prefixStyle("perspective") in _elementStyle, hasTouch: "ontouchstart" in window, hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed hasTransition: _prefixStyle("transition") in _elementStyle });
還有一些事件監(jiān)聽方面的處理函數(shù),處理class的函數(shù),處理慣性的函數(shù)momentum
me.offset = function (el) { var left = -el.offsetLeft, top = -el.offsetTop; // jshint -W084 while (el = el.offsetParent) { left -= el.offsetLeft; top -= el.offsetTop; } // jshint +W084 return { left: left, top: top }; };
me.extend(me.eventType = {}, { touchstart: 1, touchmove: 1, touchend: 1, ...略... MSPointerDown: 3, MSPointerMove: 3, MSPointerUp: 3 });
me.extend(me.ease = {}, { quadratic: { style: "cubic-bezier(0.25, 0.46, 0.45, 0.94)", fn: function (k) { return k * ( 2 - k ); } }, ....略.... });
me.tap = function (e, eventName) { var ev = document.createEvent("Event"); ev.initEvent(eventName, true, true); ev.pageX = e.pageX; ev.pageY = e.pageY; e.target.dispatchEvent(ev); }; me.click = function (e) { var target = e.target, ev; if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent // initMouseEvent is deprecated. ev = document.createEvent(window.MouseEvent ? "MouseEvents" : "Event"); ev.initEvent("click", true, true); ...略... target.dispatchEvent(ev); } };
me.getTouchAction = function(eventPassthrough, addPinch) { var touchAction = "none"; if ( eventPassthrough === "vertical" ) { touchAction = "pan-y"; } else if (eventPassthrough === "horizontal" ) { touchAction = "pan-x"; } if (addPinch && touchAction != "none") { // add pinch-zoom support if the browser supports it, but if not (eg. Chrome <55) do nothing touchAction += " pinch-zoom"; } return touchAction; };
me.getRect = function(el) { if (el instanceof SVGElement) { var rect = el.getBoundingClientRect(); return { top : rect.top, left : rect.left, width : rect.width, height : rect.height }; } else { return { top : el.offsetTop, left : el.offsetLeft, width : el.offsetWidth, height : el.offsetHeight }; } };構(gòu)造函數(shù)
先是獲取了wrapper和scroller,接著是一些能力檢測。
在這里通過eventPassthrough,scrollY,scrollX,freeScroll來配置滾動的方向。只有scrollY是默認為true,其他都是未設(shè)定undefined.
當eventPassthrough的值為vertical時,在垂直方向不使用iscroll的滾動,使用原生的滾動。為horizontal時,則水平方向如此。想要二維自由滾動,不能設(shè)置該值。
this.options.eventPassthrough = this.options.eventPassthrough === true ? "vertical" : this.options.eventPassthrough; this.options.scrollY = this.options.eventPassthrough == "vertical" ? false : this.options.scrollY; this.options.scrollX = this.options.eventPassthrough == "horizontal" ? false : this.options.scrollX; this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
接著還有其他屬性的設(shè)定,最后調(diào)用_init,refresh,scrollTo,enable等函數(shù)
一些原形上綁定的函數(shù)只調(diào)用了_initEvents函數(shù)
在這里根據(jù)配置給wrapper或是window加入了鼠標事件,pointer事件和觸摸事件,transition事件等事件的監(jiān)聽。這里用到了一種少見的事件綁定方法,在這里事件綁定的第三個參數(shù)不是常見的function,而是iscroll對象。而iscroll對象里有一個方法handleEvent,這種方式的好處就是可以傳遞this
handleEvent: function (e) { switch ( e.type ) { case "touchstart": case "pointerdown": case "MSPointerDown": case "mousedown": this._start(e); break; case "touchmove": case "pointermove": case "MSPointerMove": case "mousemove": this._move(e); break; case "touchend": case "pointerup": case "MSPointerUp": case "mouseup": case "touchcancel": case "pointercancel": case "MSPointerCancel": case "mousecancel": this._end(e); ...略... } }
保存wrapper和scroller的尺寸信息,及wrapper的位置信息。設(shè)定最大滾動距離,為負數(shù)。
接著判斷是否存在水平滾動或是垂直滾動
this.maxScrollX = this.wrapperWidth - this.scrollerWidth; this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
如果瀏覽器支持pointer,使用touchAction來限制wrapper。
最后調(diào)用resetPosition函數(shù)來判斷是否需要重置位置
保存事件的類型,如果跟已經(jīng)保存的事件類型不是同一類,不繼續(xù)執(zhí)行函數(shù)。
如果scroller在滾動狀態(tài),調(diào)用getComputedPosition函數(shù)來獲取scroller的位置,調(diào)用_translate方法讓scroller停在當前位置。
保存當前的位置信息和觸發(fā)事件的位置信息,設(shè)置狀態(tài)信息
this.initiated = utils.eventType[e.type]; this.moved = false; this.distX = 0; this.distY = 0; this.directionX = 0; this.directionY = 0; this.directionLocked = 0; this.startX = this.x; this.startY = this.y; this.absStartX = this.x; this.absStartY = this.y; this.pointX = point.pageX; this.pointY = point.pageY;
獲取事件的位置信息,對比_start中保存的位置信息,計算偏移值
var point = e.touches ? e.touches[0] : e, deltaX = point.pageX - this.pointX, deltaY = point.pageY - this.pointY,
保存新的位置信息,位移信息
this.pointX = point.pageX; this.pointY = point.pageY; this.distX += deltaX; this.distY += deltaY;
如果偏移小于10像素不執(zhí)行滾動。偏移的大小值和設(shè)定來根據(jù)判斷滾動的方向。最后調(diào)用_translate函數(shù)來滾動
根據(jù)設(shè)定,修改滾動條中的transform的值或是修改left和top的值來進行具體的滾動,保存信息到this.x和this.y
if ( this.options.useTransform ) { this.scrollerStyle[utils.style.transform] = "translate(" + x + "px," + y + "px)" + this.translateZ; } else { x = Math.round(x); y = Math.round(y); this.scrollerStyle.left = x + "px"; this.scrollerStyle.top = y + "px"; }
讓scroller滾動到整數(shù)位置,根據(jù)位移和觸發(fā)事件的時間的情況,摸你tap事件、click事件或是執(zhí)行flick事件或調(diào)用scrollTO函數(shù)進行慣性滾動。
主要是選擇動畫效果,調(diào)用__translate或是_animate來進行滾動
根據(jù)所選的動畫效果,在每一個requestAnimationFrame下調(diào)用_translate函數(shù)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94216.html
摘要:一些方法不應(yīng)該這樣不應(yīng)該漫無目的地隨手拿起一分源碼,試圖去通讀。應(yīng)該這樣精心挑選要閱讀的源碼項目。這最好是與你的編程語言你的工作內(nèi)容你的興趣所在相關(guān)的,這樣才能更切實地感受到閱讀源碼給你帶來的益處,更有動力繼續(xù)。 showImg(https://segmentfault.com/img/bVbcvmm?w=785&h=525); 怎么閱讀源碼 沒有經(jīng)驗的技術(shù)差底子薄的初級程序員,如何閱...
摘要:精讀原文介紹了學(xué)習(xí)源碼的兩個技巧,并利用實例說明了源碼學(xué)習(xí)過程中可以學(xué)到許多周邊知識,都讓我們受益匪淺。討論地址是精讀源碼學(xué)習(xí)如果你想?yún)⑴c討論,請點擊這里,每周都有新的主題,周末或周一發(fā)布。 1. 引言 javascript-knowledge-reading-source-code 這篇文章介紹了閱讀源碼的重要性,精讀系列也已有八期源碼系列文章,分別是: 精讀《Immer.js》源...
摘要:對于一個有追求的程序員來說必須讀源碼,當然閱讀源碼是一件令人頭疼的事。和差不多,想法一樣,但是和相比,搜索到的有價值結(jié)果不是很多,沒有的理想,還有一些來著百度知道。 對于一個有追求的程序員來說必須讀源碼,當然閱讀源碼是一件令人頭疼的事。閱讀別人的代碼遠比自己寫代碼要難。Linus 是Linux的早期作者,一句影響深遠的話是Read The Fucking Source Code(RTF...
閱讀 2419·2021-10-11 10:57
閱讀 1274·2021-10-09 09:59
閱讀 1986·2019-08-30 15:53
閱讀 3206·2019-08-30 15:53
閱讀 1001·2019-08-30 15:45
閱讀 727·2019-08-30 15:44
閱讀 3433·2019-08-30 14:24
閱讀 946·2019-08-30 14:21