手淘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 相关文章推荐
Javascript 生成指定范围数值随机数
Jan 09 Javascript
js 禁用只读文本框获得焦点时的退格键
Apr 25 Javascript
关于JAVASCRIPT urldecode URL解码的问题
Jan 08 Javascript
jQuery实现返回顶部效果的方法
May 29 Javascript
在Vue 中使用Typescript的示例代码
Sep 10 Javascript
vue观察模式浅析
Sep 25 Javascript
了解JavaScript中let语句
May 30 Javascript
vue发送websocket请求和http post请求的实例代码
Jul 11 Javascript
微信小程序自定义波浪组件使用方法详解
Sep 21 Javascript
Ant design vue table 单击行选中 勾选checkbox教程
Oct 24 Javascript
详解Vue中的自定义指令
Dec 07 Vue.js
关于element的表单组件整理笔记
Feb 05 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中常用的输出函数总结
2014/09/22 PHP
php插入排序法实现数组排序实例
2015/02/16 PHP
简单谈谈favicon
2015/06/10 PHP
php使用gzip压缩传输js和css文件的方法
2015/07/29 PHP
修改PHP脚本使WordPress拦截垃圾评论的方法示例
2015/12/10 PHP
php安全配置记录和常见错误梳理(总结)
2017/03/28 PHP
用Javascript实现锚点(Anchor)间平滑跳转
2009/09/08 Javascript
Js sort排序使用方法
2011/10/17 Javascript
捕获浏览器关闭、刷新事件不同情况下的处理方法
2013/06/02 Javascript
js 实现菜单上下显示附效果图
2013/11/21 Javascript
做web开发 先学JavaScript
2014/12/12 Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
2016/01/04 Javascript
基于JS实现新闻列表无缝向上滚动实例代码
2016/01/22 Javascript
微信JS-SDK坐标位置如何转换为百度地图坐标
2016/07/04 Javascript
jQuery层次选择器用法示例
2016/09/09 Javascript
Vue.js一个文件对应一个组件实践
2016/10/27 Javascript
vue进行图片的预加载watch用法实例讲解
2018/02/07 Javascript
详解适配器在JavaScript中的体现
2018/09/28 Javascript
Next.js项目实战踩坑指南(笔记)
2018/11/29 Javascript
JS如何实现手机端输入验证码效果
2020/05/13 Javascript
js实现点击上传图片并设为模糊背景
2020/08/02 Javascript
解决vue路由name同名,路由重复的问题
2020/08/05 Javascript
原生JavaScript实现拖动校验功能
2020/09/29 Javascript
python序列类型种类详解
2020/02/26 Python
Python处理mysql特殊字符的问题
2020/03/02 Python
django 模版关闭转义方式
2020/05/14 Python
Python根据指定文件生成XML的方法
2020/06/29 Python
使用CSS3实现多列布局与多背景的技巧
2016/02/29 HTML / CSS
html5中为audio标签增加停止按钮动作实现方法
2013/01/04 HTML / CSS
Canvas制作旋转的太极的示例
2018/03/09 HTML / CSS
社会学专业求职信
2014/02/24 职场文书
植树节标语
2014/06/27 职场文书
2015年社区教育工作总结
2015/05/13 职场文书
好人好事新闻稿
2015/07/17 职场文书
浅谈Python项目的服务器部署
2021/04/25 Python
Java8利用Stream对列表进行去除重复的方法详解
2022/04/14 Java/Android