技术选择如果使用react框架开发移动端,一般架构是Preact+antd-mobile+react-hammerjs+iscroll。PreactPreact是React的3kb轻量级解决方案,同样采用ES6API,具有以下优点:1.体积小,ReactV16.0有34.8kb,而Preact官网宣称只有3kb2。高性能,是最快的虚拟DOM框架之一3.生态好,提供官方preact-compat,可以无缝使用React生态中的各种组件迁移指南1:安装preact,preact-compat,preact-compat会将编译后的代码增加约2kb,但它支持npm存储库中的大多数React模块。此外,preact-compat包在Preact的基础上提供了必要的适配,使其行为与react和react-dom相同。npmi-Spreactpreact-compat2:在webpack配置resolve.alias中,将react和react-dom的路径指向preact-compat。{"resolve":{"alias":{"react":"preact-compat","react-dom":"preact-compat"}}}页面终端适配灵活解决方案,对于移动端方案,其中手淘采用Flexible布局方案,只需要在项目中引入lib-flexible库即可。flexible的本质就是JS动态修改metaViewport,主要做了以下几件事:JS动态修改meta标签为html元素添加data-dpr属性,动态修改data-dpr的值为html元素添加font-size属性,并动态修改font-size值的核心代码如下:(function(){varmetaEl=document.querySelector('meta[name="viewport"]')vardpr=0varscale=0if(!dpr&&!scale){varisIPhone=window.navigator.appVersion.match(/[iphone|ipad]/gi)vardevicePixelRatio=window.devicePixelRatioif(isIPhone){dpr=devicePixelRatio}else{dpr=1}}docEl.setAttribute('data-dpr',dpr)if(!metaEl){metaEl=document.createElement('meta');metaEl.setAttribute('name','viewport');metaEl.setAttribute('content','width=device-width,initial-scale='+scale+',maximum-scale='+scale+',minimum-scale='+scale+',user-scalable=no');文档.documentElement.firstElementChild.appendChild(metaEl);}else{metaEl.setAttribute('content','width=device-width,initial-scale='+scale+',maximum-scale='+scale+',minimum-scale='+scale+',user-可扩展性=否');}})()动态缩放视口后,在iphone6上,2pxCSS像素的显示效果为1px,而在dpr=1的设备上,一个像素的CSS1px显示为1px。为了让字体在不同手机上显示一致,需要动态修改html的font-size,页面中以rem为单位/**设置根元素font-size*当设备宽度为375(iPhone6),根元素font-size=16px*/varclientWidth=win.innerWidth||doc.documentElement.clientWidth||doc.body.clientWidthif(!clientWidth)returnvarfz=16*clientWidth/375document.style.fontSize=fz+'px'开发页面的时候可以用less或者sass写一个函数把px值转换成rem值,这样你就可以很方便的使用px。viewportschemevw(view-width)、vh(view-height)是CSS3中新加入的两个单位,分别表示viewport的宽度/高度。视口的总宽度为100vw,总高度为100vh。随着视口单元越来越多浏览器的支持,在自适应布局中可以直接使用vw。vw:1vw等于window.innerWidth的1%vh:1vh等于window.innerHeight的1%vmin:vmin的值是当前vw和vh中较小的值vmax:vmax的值是较大的值当前vw和vh的解决方案,可以使用postcss-px-to-viewport插件直接将css中的px转为vw,vh。插件参数配置如下:"postcss-px-to-viewport":{viewportWidth:750,viewportHeight:1334,unitPrecision:5,viewportUnit:'vw',selectorBlackList:[],minPixelValue:1,mediaQuery:false}两种方案vw/vh的对比,可以直接使用,不需要第三方依赖postcss-px-to-viewport插件会将css中的px转换成vw/vh单位,特别适合第三方UI框架.这其实是我们意想不到的。对于不想转换的px样式,需要额外添加一个.ignore类名,将px转换为vw/vh后,在浏览器上调试非常不方便。postcss-px-to-viewport无法将嵌入样式中的px转换为vw/vh。需要处理1px的边框问题。1px边界问题是灵活的。flexible下的1pxborder是最容易处理的,因为flexible是动态修改视口缩放比例的,所以可以直接设置border:solid1px#ddd;,但是flexible对安卓机没有做任何事情,所以线条很在Android机上很厚,而且因为选择了vw/vh方案来适配页面,所以我们不得不考虑其他的方案来处理1px的问题。border-image属性可以使用postcss-write-svg插件,代码如下:@svgsquare{height:2px;@rect{fill:var(--color,black);宽度:100%;高度:50%;}}#example{border:1pxsolidtransparent;border-image:svg(squareparam(--color#00b1ff))22stretch;}postcss-write-svg插件会将上面的代码编译成下面的代码:#example{border:1pxsolidtransparent;border-image:url("data:image/svg+xml;charset=utf-8,%3Csvgxmlns='http://www.w3.org/2000/svg'height='2px'%3E%3Crectfill='%2300b1ff'width='100%25'height='50%25'/%3E%3C/svg%3E")22stretch;}这个方案简单易用,比修改成本低pictures更简单更快,具体请参考postcss-write-svg。添加postcss-write-svg插件时,如果同时使用postcss-px-to-viewport插件,postcss-write-svg插件必须放在前面,在safari中浏览器,边框:1px实心透明;property线条将不可见,需要去掉透明。after伪类+scale在需要的元素上加上:after伪类并缩放,代码如下:#example{position:relative;}//添加1px的下边框#example:after{content:'',位置:绝对;border-bottom:solid1px#ddd;底部:0;左:0;宽度:100%;transform:scale(1,1/2)}这里的缩放因子在移动端是1/dpr,所以这里还需要使用mediaquery来缩放不同dpr下的不同倍数:@mediascreenand(-webkit-min-device-pixel-ratio:2),(min--moz-device-pixel-ratio:2),(min-resolution:2dppx){#example:after{transform:scale(1,1/2)}}@media屏幕和(-webkit-min-device-pixel-ratio:3),(min--moz-device-pixel-ratio:3),(min-resolution:3dppx){#example:after{transform:scale(1,1/3)}}该方案的缺点:难以在四个方向添加1px的边框,需要嵌套多层元素才能实现。在下边框添加1px的边框线时,该线不在元素的底部。这是因为缩放后,底部是空白区域。如果设置了bottom:-1px,则元素有overflow:hidden;属性,则边框线将不可见。点击延迟。移动端派发点击事件时,一般会有300ms的延迟。这是手机浏览器为了判断用户是否双击导致的。下次点击时,浏览器会将其视为点击事件。解决方法禁止缩放
