前言:18年12月24日項目成功上線了,在經歷了兩週的線上bug、UI以及代碼優化後,解決了很多問題,因而再完善與優化一下這個 項目。
佈局優化在這篇文章完成了 → [移動端優雅佈局實踐](),最後我使用的方案是——absolute脫離文檔流(好處是設置容器的height: 100%
,能夠直接繼承html窗口高度)。javascript
開始項目以前沒有對dpr(device pixel radio)與縮放作過多的瞭解,在項目開發的時候就將它們都直接寫死爲1了。到後來UI驗收的時候發現並無實現UI設計師預期的細線效果。我在解決這個問題的時候纔去認真看了一下dpr的介紹。這篇詳解dpr的文章寫得還不錯。css
從概念來講,dpr就是設備的物理像素與設備獨立像素(也就是css邏輯像素,如下就稱爲css邏輯像素)的比率。html
好比:iPhone 6的分辨率是750*1334,window.screen.width
(css邏輯像素)爲375,所以java
dpr = 750 /375 = 2
再好比:iPhone X的分辨率是1125*2436,window.screen.width
(css邏輯像素)也是375,所以node
dpr = 1125 /375 = 3
那麼dpr有什麼用呢?react
在這以前先提一下咱們移動端必備的一個meta
標籤:webpack
<meta name="viewport" content="width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=no" />
device-width在html中也一樣被解讀爲理想(基準)視口的寬度,即320px,375px,414px,這裏的px就是指css像素,一般也被稱爲邏輯像素;那咱們能夠認爲html中的css像素的顯示尺寸應該和NA中的pt、dp的顯示尺寸相等。
經過這個meta標籤,咱們能夠實現initial-scale=1
初始縮放100%,就能夠達到1px的css邏輯像素 = 眼睛在設備上看起來的1px
,換句話說body { width: 375px; }
能夠在iPhone 6上充滿豎屏的整個寬度。git
那麼問題就來了,若是咱們要給一個盒子加上一個1px的細線:border-bottom: 1px solid red;
。那麼在iPhone 6上真的是1px嗎?github
iPhone 6真機截圖(寬度爲702px):web
能夠看出高度明顯不止1像素。這就是因爲dpr形成的,由於iPhone 6的dpr爲2,且縮放比例爲100%,1px的css渲染出來就是2px物理像素。
這就是咱們UI粑粑和產品們不滿意的地方。
那接下來如何去解決這個問題呢?
根據設備的dpr來動態計算縮放比例,以及根節點的font-size
。
// rem.js (function(doc, win) { var docEl = doc.documentElement, dpr = Math.min(win.devicePixelRatio, 3); dpr = window.top === window.self ? dpr : 1; //被iframe引用時,禁止縮放 var scale = 1 / dpr, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; docEl.dataset.dpr = dpr; var metaEl = doc.createElement('meta'); metaEl.name = 'viewport'; metaEl.content = 'initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ',user-scalable=no,viewport-fit=cover'; docEl.firstElementChild.appendChild(metaEl); var recalc = function() { var width = docEl.clientWidth; // 大於1280按1280來算 if (width / dpr > 1280) { width = 1280 * dpr; } // px : rem = 100 : 1 docEl.style.fontSize = 100 * (width / 375) + 'px'; }; recalc(); if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); })(document, window);
若是有顯示富文本元素,則須要處理富文本元素的樣式
移動端爲了適配不一樣的機型,使用rem
爲單位是一個不錯的選擇,並且咱們也一直在用它。
這裏除了根據dpr來計算initial-scale
,還調整了根節點的font-size
,以致於在縮放的時候可以還原到視窗大小(由於要縮放,因此要相應的增長rem
的基數)。
這樣咱們上面寫的border-bottom: 1px solid red;
在這個方案顯示出來就是這樣的:
哇咔咔,能夠看出明顯變細了,這纔是咱們UI粑粑們想要的O(∩_∩)O~~
可是這樣的設置在結合ant-design-mobile
的時候,發現ant-design-mobile
的組件都被縮小了。原來是,它的元素都是以px爲單位,而咱們縮放前沒有對它的最小單位乘以相應的基數。那麼,咱們須要給它配置一個基數!
查文檔發現ant-design-mobile
提供了主題配置,並且它提供了一個@hd
的變量作爲長度基本單位,它的默認值是1px
。
@hd
設置爲0.01rem
就能夠解決問題。這個主題配置的文檔是以webpack項目來作的例子。那如何在next.js
項目中完成自定義配置呢?
我在next.js的examples中沒有找到我所須要的example,不過找到了兩個相關的例子:一個是with-antd-mobile,一個是with-ant-design-less。第二個是ant-design
的自定義主題配置,那應該就能夠仿照這個example去增長with-antd-mobile的自定義主題配置。
這裏提一下,這個
with-antd-mobile在我寫
Next框架與主流工具的整合以後更新了
next.config.js
的配置,這裏也改爲了最新的配置。
npm i @zeit/next-less @zeit/next-css less less-vars-to-js -S
.babelrc
配置{ "presets": ["next/babel"], "plugins": [ [ "import", { "libraryName": "antd-mobile", "style": true } ] ] }
next.config.js
配置/* eslint-disable */ const withCSS = require('@zeit/next-css'); const withSass = require('@zeit/next-sass'); const withLess = require('@zeit/next-less'); const lessToJS = require('less-vars-to-js'); const fs = require('fs'); const path = require('path'); // Where your antd-custom.less file lives const themeVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, './antd-custom.less'), 'utf8')); // fix: prevents error when .less files are required by node if (typeof require !== 'undefined') { require.extensions['.less'] = file => {}; require.extensions['.css'] = file => {}; } module.exports = withCSS( withLess( withSass({ lessLoaderOptions: { javascriptEnabled: true, modifyVars: themeVariables } }) ) );
antd-custom.less
@hd: 0.01rem;
重啓項目,就大功告成了。
antd-mobile
的Toast.info()
組件在顯示的時候不能點擊背景就消失,與原生的Toast有些差別,爲了體驗,這裏再作了一層封裝,在點擊背景的時候隱藏Toast。
// utils/toast.js static info = (content, duration, onClose, mask) => { Toast.info(content, duration, onClose, mask); const toastElement = document.getElementsByClassName('am-toast-mask')[0]; toastElement && toastElement.addEventListener('click', () => { Toast.hide(); onClose && onClose(); }); };
antd-mobile
的loading圖在Android上有些怪異,這裏也自定義了Loading:
static loading = (content, duration, onClose, mask) => { Toast.info( <div> <svg className="rotate360-800" width="0.26rem" height="0.26rem" viewBox="0 0 26 26"> <title>加載</title> <desc>Created with Sketch.</desc> <g id="首頁" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd"> <g transform="translate(-185.000000, -519.000000)" fill="#FFFFFF" id="加載"> <g transform="translate(185.000000, 519.000000)"> <g id="分組" transform="translate(0.625011, 0.625011)"> <path d="M12.3750144,0.0259531552 C5.53983848,0.0259531552 0,5.56600648 0,12.4009676 C0,19.2359286 5.53983848,24.775982 12.3750144,24.775982 C19.2099755,24.775982 24.7500288,19.2359286 24.7500288,12.4009676 C24.7500288,5.56579163 19.2099755,0.0259531552 12.3750144,0.0259531552 Z M12.3750144,22.028385 C7.05736759,22.028385 2.74781179,17.7185714 2.74781179,12.4009676 C2.74781179,7.08332074 7.05741056,2.7735501 12.3750144,2.7735501 C17.6926612,2.7735501 22.0026467,7.08336371 22.0026467,12.4009676 C22.0026467,17.7186144 17.6926182,22.028385 12.3750144,22.028385 Z" id="形狀" fillOpacity="0.2" fillRule="nonzero" /> <path d="M12.3749972,0.0259402646 L12.3750144,2.77353721 C17.6926612,2.77353721 22.0026467,7.08335082 22.0026467,12.4009547 L24.7500116,12.4009547 C24.7500116,5.56577874 19.2099583,0.0259402646 12.3749972,0.0259402646 Z" id="路徑" /> </g> </g> </g> </g> </svg> <div style={{ fontSize: '0.12rem' }}>{content}</div> </div>, duration, onClose, mask ); };
一個項目須要在不斷的優化與完善中才能變得更好。搭建項目是對一個項目負責人很大的考驗,若是在項目設計的初期有許多的問題沒有考慮到,就頗有可能致使優化的時候須要耗費很大的精力。
總之,不要逃避困難與問題,這些都是成長路上不可或缺的。