淘寶lib-flexible.js插件註釋版

;

(function(win, lib) {
    var doc = win.document;

    var docEl = doc.documentElement;

    /**

     * 獲取例如<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">的元素

     * */

    var metaEl = doc.querySelector('meta[name="viewport"]');

    /**

     * 獲取例如<meta name="flexible" content="initial-dpr=2,maximum-dpr=3" />的元素

     * 其中initial-dpr會把dpr強制設置爲給定的值,maximum-dpr會比較系統的dpr和給定的dpr,取最小值。注意:這兩個參數只能選其一。

     * */

    var flexibleEl = doc.querySelector('meta[name="flexible"]');

    // 屏幕可視區寬度叫設備獨立像素,device independent pixels,簡稱dip或dp。屏幕可以顯示的顯示的實際像素數叫作物理像素。

    // 定義設備像素比,像素比window.devicePixelRatio=物理像素/設備獨立像素(dips)

    var dpr = 0;

    // 定義視口縮放比例

    var scale = 0;

    // 定義setTimeout返回的值

    var tid;

    // 獲取或定義flexible對象

    var flexible = lib.flexible || (lib.flexible = {});

    // 若是存在視口的meta的標籤

    if (metaEl) {
        console.warn('將根據已有的meta標籤來設置縮放比例');

        var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);

        if (match) {
            // 用正則表達式匹配出縮放比例

            scale = parseFloat(match[1]);

            // 根據縮放比例獲取設備像素比

            dpr = parseInt(1 / scale);

        }

    } else if (flexibleEl) {
        // 若是存在彈性meta標籤,獲取content屬性

        var content = flexibleEl.getAttribute('content');

        // 若是屬性存在

        if (content) {
            var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);

            var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);

            // 若是存在最初的設備像素比

            if (initialDpr) {
                dpr = parseFloat(initialDpr[1]);

                scale = parseFloat((1 / dpr).toFixed(2));

            }

            // 若是存在最大極限的設備像素比

            if (maximumDpr) {
                dpr = parseFloat(maximumDpr[1]);

                scale = parseFloat((1 / dpr).toFixed(2));

            }

        }

    }

    // 若是設備像素比和縮放比例都沒有定義

    if (!dpr && !scale) {
        // 判斷是不是安卓平臺

        var isAndroid = win.navigator.appVersion.match(/android/gi);

        // 判斷是不是ios平臺

        var isIPhone = win.navigator.appVersion.match(/iphone/gi);

        // 獲取當前設備的設備像素比

        var devicePixelRatio = win.devicePixelRatio;

        if (isIPhone) {
            // iOS下,對於2和3的屏,用2倍的方案,其他的用1倍方案

            if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
                dpr = 3;

            } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
                dpr = 2;

            } else {
                dpr = 1;

            }

        } else {
            // 其餘設備下,仍舊使用1倍的方案

            dpr = 1;

        }

        // 縮放比例,等於設備像素比的倒數

        scale = 1 / dpr;

    }

    // 給html添加data-dpr屬性

    docEl.setAttribute('data-dpr', dpr);

    // 若是視口的meta標籤不存在,則從新建立

    if (!metaEl) {
        // 建立meta標籤

        metaEl = doc.createElement('meta');

        // 給meta標籤增長name屬性,指定爲視口

        metaEl.setAttribute('name', 'viewport');

        // 給meta標籤設置content屬性,指定最初的最大的縮放比例和禁止用戶手動縮放

        metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

        // docEl.firstElementChild爲head標籤  判斷有沒有head標籤

        if (docEl.firstElementChild) {
            // 把meta標籤加入到head標籤中

            docEl.firstElementChild.appendChild(metaEl);

        } else {
            // 若是不存在head標籤,則建立一個div來包裹meta標籤

            var wrap = doc.createElement('div');

            wrap.appendChild(metaEl);

            // 插入文檔流

            doc.write(wrap.innerHTML);

        }

    }

    // 刷新人

    function refreshRem() {
        // 獲取可視區域的寬度

        var width = docEl.getBoundingClientRect().width;

        // 寬度除以設備像素比等於按比例縮放後的寬度,若是這個寬度大於540,那就設置寬度爲540乘以設備像素比

        // 就是設置屏幕的寬度極限

        if (width / dpr > 540) {
            width = 540 * dpr;

        }

        // 定義1個rem等於寬度的十分之一

        var rem = width / 10;

        // 給html標籤綁定字號 字號等於一個rem

        docEl.style.fontSize = rem + 'px';

        // 給flexiable對象增長rem屬性

        flexible.rem = win.rem = rem;

    }

    // 監聽窗口變更

    win.addEventListener('resize',

        // 這裏運用了函數防抖

        function() {
            // 清除tid

            clearTimeout(tid);

            // 建立tid,300毫秒後執行refreshRem

            tid = setTimeout(refreshRem, 300);

        },

        false);

    // 監聽頁面展現事件

    win.addEventListener('pageshow',

        function(e) {
            // event.persisted從緩存中獲取時爲true不然爲false

            if (e.persisted) {
                clearTimeout(tid);

                tid = setTimeout(refreshRem, 300);

            }

        },

        false);

    // 當dom加載完成時

    if (doc.readyState === 'complete') {
        // 給body設置字號爲12乘以設備像素比

        doc.body.style.fontSize = 12 * dpr + 'px';

    } else {
        // 當初始的 HTML 文檔被徹底加載和解析完成以後

        doc.addEventListener('DOMContentLoaded',

            function(e) {
                // 給body設置字號爲12乘以設備像素比

                doc.body.style.fontSize = 12 * dpr + 'px';

            },

            false);

    }

    // 刷新rem大小

    refreshRem();

    // 給flexible對象增長屬性

    flexible.dpr = win.dpr = dpr;

    flexible.refreshRem = refreshRem;

    // rem轉爲px

    flexible.rem2px = function(d) {
            // 參數乘以一個rem表明的px值

            // parseFloat() 函數可解析一個字符串,並返回一個浮點數。該函數指定字符串中的首個字符是不是數字。若是是,則對字符串進行解析,直到到達數字的末端爲止,而後以數字返回該數字,而不是做爲字符串。

            var val = parseFloat(d) * this.rem;

            // 若是參數爲字符串而且含有rem字符串

            if (typeof d === 'string' && d.match(/rem$/)) {
                // 拼裝px

                val += 'px';

            }

            return val;

        }

        //px轉爲rem

    flexible.px2rem = function(d) {
        // 參數除以rem的長度

        var val = parseFloat(d) / this.rem;

        // 若是參數爲字符串而且含有px字符串

        if (typeof d === 'string' && d.match(/px$/)) {
            val += 'rem';

        }

        return val;

    }

 

})(window, window['lib'] || (window['lib'] = {}));
相關文章
相關標籤/搜索