手淘flexible.js框架使用和源代碼講解


手淘框架是一個用來適配移動端的js框架,下面我們來講解一下如何使用手淘的這套框架。

其實手淘框架的核心原理就是根據不同的width給網頁中html跟節點設置不同的font-size,然后所有的距離大小都用rem來代替,這樣就實現了不同大小的屏幕都適應相同的樣式了,首先我們來說一下常用的移動設備。

iphone6:    375px*667px  實際像素:750px*1334px

iphone5:   320px*568px   實際像素:640px*1136px

iphone4:   320px*480px   實際像素:640px*960px

nexus5X(安卓): 411px *731px 實際像素:411px*731px

以上數據都來自於chrome瀏覽器- -!!!

其實我們的iphone手機都是視網膜屏幕,所以我們的實際像素因該是無力像素*視網膜屏的倍數。

然而我們在實際的開發中ui給出的圖一般都是750X1334的,其實iphone6的像素和ui設計的像素是一樣大小的,但是我們的開發如果都是按照6的px來設計,那么我們的其它比6小尺寸屏幕的所有設備都會面臨width不夠的問題。flexible就完美的解決了這個問題。

應用中我們只要設置好他的公共比的像素就ok了,比如說如果ui圖的像素是750,那我們需要的就是750/10,我們需要的就是75,我們所有的width的固定px就都可以變換成用rem像素代替實現樣式統一例如我們width需要200px那么我們就可以這樣寫:

width=200rem/75;從而實現樣式的兼容(特別注意:因為css不支持樣式的計算,我們需要用less活着sass類似的css編譯執行就可以得到最終的rem的值了)

另外,我們根據不同dpr可以設置一些不同的樣式來實現視網膜屏幕的高清屏幕!

[data-dpr="1"] .selector {
width: 10px;
height: 32px;
font-size: 14px;
}
[data-dpr="2"] .selector {
width: 20px;
height: 64px;
font-size: 28px;
}

我們根據不同的自定義屬性data-dpr來設置不同的width和height 從而達到不同dpr屏幕具有不同的屬性!(這個位置一般用來處理圖片。。)

下面我們來講解一下flexible的源代碼:

;(function(win, lib) {

})(window, window['lib'] || (window['lib'] = {}));

首先這個最外層結構是最基本的封裝類庫的方法:函數立即調用,這樣可以防止封裝方法污染全局變量,jquery的源碼也是一樣的道理!

    var doc = win.document;
    var docEl = doc.documentElement;
    var metaEl = doc.querySelector('meta[name="viewport"]');
    var flexibleEl = doc.querySelector('meta[name="flexible"]');
    var dpr = 0;
    var scale = 0;
    var tid;
    var flexible = lib.flexible || (lib.flexible = {});

doc取文檔的document對象

docEl取到了我們html為根的整個dom樹,后期我們需要向html插入dpr和font-size就是用這個屬性

metaEl取meta標簽里面name=viewport的元素,沒有返回空,為了判斷是否有自己設置的meta值來做一些邏輯

flexibleEl取meta標簽里面name=flexible的元素,沒有返回空,為了判斷用戶是否自己手動的設置了一些meta值

dpr表示的是取你手機屏幕的dpr值

scale表示取你meta里面的scale,會根據不同的scale設置dpr

我們需要了解的大概就是上面的這些需要用到的屬性!

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

 

這段代碼是判斷你的meta標簽里面是不是設置了name=viewport屬性,如果你設置了viewport並且設置了initial-scale(初始屏幕的大小)我們將取到這個值作為dpr(做了邏輯運算,如果你的頁面初始的放大為二,那么我們的dpr會設置成0)

同理我們如果動態設置了meta我們直接就取出來然后設置dpr和scale

    if (!dpr && !scale) {
        var isAndroid = win.navigator.appVersion.match(/android/gi);
        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;
    }

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

之后如果我們動態設置了scale或者設置了meta標簽里面的name=flexible的inital-scale,那么我們就根據自己設置的dpr在判斷iphone手機的retina屏幕的dpr比值判斷不同型號的倍數,最后我們在html上設置了data-dpr自定義屬性。

   if (!metaEl) {
        metaEl = doc.createElement('meta');
        metaEl.setAttribute('name', 'viewport');
        metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
        if (docEl.firstElementChild) {
            docEl.firstElementChild.appendChild(metaEl);
        } else {
            var wrap = doc.createElement('div');
            wrap.appendChild(metaEl);
            doc.write(wrap.innerHTML);
        }
    }

之后當我們之前沒有設置metaEl標簽的話,那么需要我們手動的去創建meta標簽,實現移動端的適配

     function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }

    win.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
    }, false);
    win.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 300);
        }
    }, false);

這段代碼的目的就是監聽window里面的resize和pageshow方法來實現css樣式的重繪。

函數里面就是實現取到當前設備的width之后根據width計算出rem的具體值,rem代表html的font-size,這里的rem代表的是一個自定義的rem,而不是rem屬性!

    if (doc.readyState === 'complete') {
        doc.body.style.fontSize = 12 * dpr + 'px';
    } else {
        doc.addEventListener('DOMContentLoaded', function(e) {
            doc.body.style.fontSize = 12 * dpr + 'px';
        }, false);
    }

之后我們判斷document對象是否處於complete狀態,如果完成狀態我們給body一個font-size=12*dpr的值,否則我們判斷dom加載方法來實現body中的font-size的設置。這個設置是為了頁面中字體的大小,而html中的font-size是為了設置頁面的height,width等屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM