移動端適配原理:flexiable.js和px2rem結合方案的一點理解總結

  1. 經過 flexiable.js 實現動態計算根元素 htmlfontSize 值,以保證明際設備視口尺寸 (與meta[name="viewport"]標籤密切相) 永遠等於10rem
  2. 經過獲取當前設備像素比dpr後, flexiable.js 動態設置 meta[name="viewport"] 標籤,根據dpr進行scale值的設置(scale值直接會影響視口的實際尺寸,即設備尺寸/scale ===視口的實際尺寸 )

場景以下: 視覺稿:750*1334(2倍) 適配引入: flexiable.js + px2rem-loader div尺寸:600pxcss

  1. iphone6/7/8 375*667 [window.devicePixelRatio === 2] => dpr === 2 => scale === 1/dpr === 1/2 === 0.5 => 頁面插入 <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"> => 根元素fontSize === (實際設備尺寸/viewport[scale] === 375/0.5 === 750) / 10 === 75px => 600px 通過px2rem-loader 處理,600 /75 === 8rem其中 75 爲按照實際視覺稿的尺寸計算的1rem對應的值,即 750/10

即此時div尺寸爲8rem,永遠是相對與根元素的尺寸進行等比例縮放,從而實現自適應尺寸佈局。即此時8rem實際的尺寸爲 8*75 === 600px 此時設備寬度爲375px,可是此時meta[name="viewport"] scale 爲 0.5,故實際600px對應的設備寬度僅爲300px(600px*0.5)自適應完成html

  1. iphone6/7/8 Plus 414*736 [window.devicePixelRatio === 3] => dpr === 3 => scale === 1/dpr === 1/3 === 0.3333333333 => 頁面插入 <meta name="viewport" content="initial-scale=0.3333333333, maximum-scale=0.3333333333, minimum-scale=0.3333333333, user-scalable=no"> => 根元素fontSize === (實際設備尺寸/viewport[scale] === 414/0.3333333333 === 1242) / 10 === 124.2px => 600px 通過px2rem-loader 處理,600 /75 === 8rem其中 75 爲按照實際視覺稿的尺寸計算的1rem對應的值,即 750/10

即此時div尺寸爲8rem,永遠是相對與根元素的尺寸進行等比例縮放,從而實現自適應尺寸佈局。即此時8rem實際的尺寸爲 8*124.2 === 993.6px 此時設備寬度爲414px,可是此時meta[name="viewport"] scale 爲 0.3333333333,故實際600px對應的設備寬度僅爲331.2px(993.6px*0.3333333333)自適應完成react

綜上所述:設計稿的600px iphone6/7/8 375*667 dpr = 2 實際看到的爲 300px iphone6/7/8 Plus 414*736 dpr = 3 實際看到的爲 331.2px 實際根據rem與根元素的比例關係進行適配webpack

// [flexiable.js](<https://github.com/posuihushui/flexible.js>)

//建立meta標籤,設置初始比、最小比和最大比均爲scale值,並將其插入到頁面
//設置了縮放比,那麼至關於這個屏幕渲染在一個被放大的畫布之上。
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);
    }
}

// 自定義頁面元素的fontsize,方便rem的配置
function refreshRem(){
    var docEl = window.document.documentElement;
// 重點:經過getBoundingClientRect()獲取的是實際渲染的畫布尺寸;(與meta[name="viewport"]標籤密切相關)
// 即:若是設置initial-scale爲0.5,deviceWidth(iphone6s)爲375,則width = 375 / 0.5 = 750
// 即:若是設置initial-scale爲0.3,deviceWidth(iphone6s)爲375,則width = 375 / 0.3 = 1250
    var width = docEl.getBoundingClientRect().width;
    
		// 限制最大fontSize爲64px
    if (width / dpr > 640) {
        width = 640 * dpr;
    }

		// 永遠保證:實際設備視口寬度(與meta[name="viewport"]標籤密切相關) === 10rem
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}

// 監聽[resize|pageshow]觸發更新設置根元素fontSize值
window.addEventListener('resize', function() {
    clearTimeout(tid);
    tid = setTimeout(refreshRem, 300);
}, false);
window.addEventListener('pageshow', function(e) {
    if (e.persisted) {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
    }
}, false);
複製代碼
// 經過使用react-app-rewired和customize-cra對默認webpack自定義添加px2rem-loader配置
// 參考源碼 [customize-cra/src/customizers/webpack.js](<https://github.com/arackaf/customize-cra/blob/master/src/customizers/webpack.js>)
// 參考配置 [px2rem-loader配置](<https://github.com/Jinjiang/px2rem-loader>)

const { override } = require("customize-cra");

const addPx2remLoader = (options) => (config) => {
	// 獲取config全部loaders配置
  const loaders = config.module.rules.find((rule) =>
    Array.isArray(rule.oneOf)
  ).oneOf;
	
	// 獲取針對/\.css$/文件的loader配置
  const cssLoader = loaders.find((rule) => {
    return rule.test && rule.test.toString() === "/\\.css$/";
  });
	
	// 追加px2rem-loader預處理loader
  cssLoader.use = [
    ...cssLoader.use,
    {
      loader: "px2rem-loader",
	// 採用參數傳遞px2rem-loader相關配置項
      options,
    },
  ];

  return config;
};

module.exports = override(
  addPx2remLoader({
    remUnit: 75,
    remPrecision: 8,
  })
);
複製代碼

下面分別附上flexiable.js和px2rem的源碼地址(一、3): GitHub - posuihushui/flexible.js: 手機淘寶flexible.js解讀git

webpack配置相關:customize-cra/webpack.js at master · arackaf/customize-cragithub

GitHub - Jinjiang/px2rem-loader: Webpack loader for px2rem css fileweb

相關文章
相關標籤/搜索