手淘flexible.js框架使用和源代码讲解小结


Posted in Javascript onOctober 15, 2018

手淘框架是一个用来适配移动端的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等属性。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery的一些注意
Dec 06 Javascript
Iframe自适应高度绝对好使的代码 兼容IE,遨游,火狐
Jan 27 Javascript
js静态方法与实例方法分析
Jul 04 Javascript
如何让DIV可编辑、可拖动示例代码
Sep 18 Javascript
javascript数据类型示例分享
Jan 19 Javascript
Backbone.js的Hello World程序实例
Jun 19 Javascript
javascript实现拖动元素交换位置
Nov 29 Javascript
详解在Vue中通过自定义指令获取dom元素
Mar 04 Javascript
vue封装第三方插件并发布到npm的方法
Sep 25 Javascript
BootStrap点击保存后实现模态框自动关闭的思路(模态框)
Sep 26 Javascript
Vue.js的动态组件模板的实现
Nov 26 Javascript
浅谈一种让小程序支持JSX语法的新思路
Jun 16 Javascript
javascript匿名函数中的'return function()'作用
Oct 15 #Javascript
Vue Cli3 创建项目的方法步骤
Oct 15 #Javascript
Vue-Router基础学习笔记(小结)
Oct 15 #Javascript
vue安装和使用scss及sass与scss的区别详解
Oct 15 #Javascript
ndm:NPM的桌面GUI应用程序
Oct 15 #Javascript
vue基于element-ui的三级CheckBox复选框功能的实现代码
Oct 15 #Javascript
vue+axios+promise实际开发用法详解
Oct 15 #Javascript
You might like
php+dojo 的数据库保存拖动布局的一个方法dojo 这里下载
2007/03/07 PHP
必须收藏的php实用代码片段
2016/02/02 PHP
网页自动跳转代码收集
2009/09/27 Javascript
重载toString实现JS HashMap分析
2011/03/13 Javascript
实现只能输入数字的input不用replace方法
2013/09/12 Javascript
提取jquery的ready()方法单独使用示例
2014/03/25 Javascript
Jquery实现鼠标移动放大图片功能实例
2015/03/25 Javascript
javascript组合使用构造函数模式和原型模式实例
2015/06/04 Javascript
javascript中Array()数组函数详解
2015/08/23 Javascript
JS实现兼容性好,自动置顶的淘宝悬浮工具栏效果
2015/09/18 Javascript
JS实现获取键盘按下的按键并显示在页面上的方法
2015/11/04 Javascript
js 判断一个数字是不是2的n次方幂的实例
2017/11/26 Javascript
Vue学习之组件用法实例详解
2020/01/06 Javascript
python虚拟环境 virtualenv的简单使用
2020/01/21 Javascript
JavaScript观察者模式原理与用法实例详解
2020/03/10 Javascript
WebStorm无法正确识别Vue3组合式API的解决方案
2021/02/18 Vue.js
[41:17]完美世界DOTA2联赛PWL S3 access vs CPG 第二场 12.13
2020/12/17 DOTA
java直接调用python脚本的例子
2014/02/16 Python
python写日志封装类实例
2015/06/28 Python
mac安装scrapy并创建项目的实例讲解
2018/06/13 Python
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
对python3标准库httpclient的使用详解
2018/12/18 Python
python实现将多个文件分配到多个文件夹的方法
2019/01/07 Python
Python实现九宫格式的朋友圈功能内附“马云”朋友圈
2019/05/07 Python
python将print输出的信息保留到日志文件中
2019/09/27 Python
详解python中groupby函数通俗易懂
2020/05/14 Python
Python 在函数上添加包装器
2020/07/28 Python
BIBLOO捷克:购买女装、男装、童装、鞋和配件
2017/01/27 全球购物
Marriott国际:万豪国际酒店查询预订
2017/09/25 全球购物
公司会议开幕词
2015/01/29 职场文书
初中生思想道德自我评价
2015/03/09 职场文书
学校光盘行动倡议书
2015/04/28 职场文书
本科毕业答辩开场白
2015/05/27 职场文书
学生检讨书范文
2019/06/24 职场文书
常用的文件对应的MIME类型汇总
2022/04/26 HTML / CSS
app场景下uniapp的扫码记录
2022/07/23 Java/Android