手淘框架是一個用來適配移動端的js框架,下面咱們來說解一下如何使用手淘的這套框架。css
其實手淘框架的核心原理就是根據不一樣的width給網頁中html跟節點設置不一樣的font-size,而後全部的距離大小都用rem來代替,這樣就實現了不一樣大小的屏幕都適應相同的樣式了,首先咱們來講一下經常使用的移動設備。html
iphone6: 375px*667px 實際像素:750px*1334pxjquery
iphone5: 320px*568px 實際像素:640px*1136pxandroid
iphone4: 320px*480px 實際像素:640px*960pxchrome
nexus5X(安卓): 411px *731px 實際像素:411px*731px瀏覽器
以上數據都來自於chrome瀏覽器- -!!!sass
其實咱們的iphone手機都是視網膜屏幕,因此咱們的實際像素因該是無力像素*視網膜屏的倍數。app
然而咱們在實際的開發中ui給出的圖通常都是750X1334的,其實iphone6的像素和ui設計的像素是同樣大小的,可是咱們的開發若是都是按照6的px來設計,那麼咱們的其它比6小尺寸屏幕的全部設備都會面臨width不夠的問題。flexible就完美的解決了這個問題。框架
應用中咱們只要設置好他的公共比的像素就ok了,好比說若是ui圖的像素是750,那咱們須要的就是750/10,咱們須要的就是75,咱們全部的width的固定px就均可以變換成用rem像素代替實現樣式統一例如咱們width須要200px那麼咱們就能夠這樣寫:less
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等屬性。