iscroll-lite源碼瀏覽

背景

近來開闢挪動端項目用到了iscroll,踩了不少坑,因而瀏覽源碼加深下對這個東西的相識。
本次瀏覽的是iscroll-lite,包含了重要的功用,比完整版少了鼠標滾輪,轉動后對齊到特定位置,按鍵綁定及定製轉動條等功用。

主體組織

以當前的5.2版本為例,前三百行是東西函數,封裝了一些東西。三百行到四百行是組織函數IScroll,起到設置和初始化的結果。四百行到一千修正了IScroll的原型,給IScroll實例加上了種種要領。末了是模塊化相干的推斷。整體的組織是很清楚的。

東西函數

_prefixStyle

用於瀏覽器兼容。

    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);
    }
才能檢測

推斷瀏覽器是不是支撐相干的特徵

    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
    });

另有一些事宜監聽方面的處置懲罰函數,處置懲罰class的函數,處置懲罰慣性的函數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 );
            }
        },
        ....略....
    });
tap和click的事宜模仿
    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);
        }
    };
touchAction的設定
    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
            };
        }
    };

組織函數

先是獵取了wrapper和scroller,接着是一些才能檢測。

在這裏經由過程eventPassthrough,scrollY,scrollX,freeScroll來設置轉動的方向。只要scrollY是默以為true,其他都是未設定undefined.
當eventPassthrough的值為vertical時,在垂直方向不運用iscroll的轉動,運用原生的轉動。為horizontal時,則程度方向云云。想要二維自在轉動,不能設置該值。

    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;

接着另有其他屬性的設定,末了挪用_init,refresh,scrollTo,enable等函數

一些真相上綁定的函數

_init

只挪用了_initEvents函數

_initEvents

在這裏依據設置給wrapper或是window加入了鼠標事宜,pointer事宜和觸摸事宜,transition事宜等事宜的監聽。這裏用到了一種少見的事宜綁定要領,在這裏事宜綁定的第三個參數不是罕見的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);
            ...略...
            }
        }
           
refresh

保留wrapper和scroller的尺寸信息,及wrapper的位置信息。設定最大轉動間隔,為負數。
接着推斷是不是存在程度轉動或是垂直轉動

        this.maxScrollX        = this.wrapperWidth - this.scrollerWidth;
        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;

假如瀏覽器支撐pointer,運用touchAction來限定wrapper。
末了挪用resetPosition函數來推斷是不是須要重置位置

_start

保留事宜的範例,假如跟已保留的事宜範例不是統一類,不繼承實行函數。
假如scroller在轉動狀況,挪用getComputedPosition函數來獵取scroller的位置,挪用_translate要領讓scroller停在當前位置。
保留當前的位置信息和觸發事宜的位置信息,設置狀況信息

    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;
_move

獵取事宜的位置信息,對照_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像素不實行轉動。偏移的大小值和設定來依據推斷轉動的方向。末了挪用_translate函數來轉動

_translate

依據設定,修正轉動條中的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';
        }
_end

讓scroller轉動到整數位置,依據位移和觸發事宜的時候的狀況,摸你tap事宜、click事宜或是實行flick事宜或挪用scrollTO函數舉行慣性轉動。

scrollTo

重如果挑選動畫結果,挪用__translate或是_animate來舉行轉動

_animate

依據所選的動畫結果,在每個requestAnimationFrame下挪用_translate函數

    原文作者:hpoenixf
    原文地址: https://segmentfault.com/a/1190000014358218
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞