手淘flexible.js框架使用和源代码讲解小结
手淘框架是一个用来适配移动端的js框架,下面我们来讲解一下如何使用手淘的这套框架。
基本概念
1、视窗viewport
可能写过移动端的朋友就知道viewport是什么意思。
如果你不知道的话,可以简单理解成:浏览器的可视区窗口。可能在pc端,viewport就是浏览器窗口的宽度高度。但在移动端设备上却就有点复杂,具体的详细介绍我就不介绍啦!可以自行百度...
2、物理像素
物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。
3、设备独立像素
设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说css像素),然后由相关系统转换为物理像素。
4、css像素
css像素是一个抽像的单位,主要使用在浏览器上,用来精确度量web页面上的内容。一般情况之下,css像素称为与设备无关的像素(device-independent pixel),简称dips。
5、屏幕密度
屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(ppi)。
6、设备像素比
设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:
设备像素比 = 物理像素 / 设备独立像素
众所周知,iphone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt。
其实手淘框架的核心原理就是根据不同的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等属性。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Oracle用户被锁原因及解决办法