libflexible源码阅读

摘要:
前言最近,需要一款移动终端产品,并且需要一个高峰时期。在参考了天猫的flexbox布局和淘宝的rem布局方案后,选择了libflexible。缩放){varisAndroid=win.navigator.appVersion.match;varisIPhone=win.nviigator_appVersion.match;vardevicePixelRatio=win.devicePixel比率;如果{//在iOS下,对于2个和3个屏幕,使用两倍的解决方案,对于其余屏幕,如果(devicePixelRatio>=3&&(!Dpr | Dpr>=2)){Dpr=2;}否则{dpr=1;}}否则{//在其他设备下,我们仍然使用1次解dpr=1;}比例=1/dpr;}接下来,如果我们没有以的方式预设dpr,也没有以的方式预置缩放,那么flexibe将开始根据设备的dpr动态计算缩放。
前言

最近需要一款移动端的产品,当时需要赶工期,在参考了天猫的flexbox布局和手淘的
rem布局方案后,决定选用libflexible。做完项目之后,稍有空闲时间,决定看看libflexible
如何实现动态设置根元素的字体,从而通过rem的方式改变其他元素大小

正文

首先我们看一下flexible需要哪些属性

;(function(win, lib) {
    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 = {});

在函数运行时,我们需要将windows对象注入,然后在看看windows下是否已经存在lib(即是否已经有
使用过flexible)了,注入完之后,我们依次获得doc,docEl,metaEl,flexibleEl,其中metaEl
是为了判断我们是否已经有预设好的viewport,flexibleEl则是判断我们已经手动设置好dpr来避免
flexible库动态设置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);
     }
 }

如果metaEl存在的话,意味着页面上存在形如<meta name="viewport" content="initial-scale=1">的标签,此时我们已经明确了我们需要的缩放,不再需要flexible的介入,缩放值scale直接
使用预设的initial-scale,通过我们预设的的缩放,我们的layout viewport将会是 ideal viewport/scale,如果我们的initual-scale为1的话
且ideal为414px的话,我们的layout viewport将会是414px

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));
           }
       }
   }

如果我们没有设置初始的viewport但是有<meta name="flexible" content="initial-dpr=2" />这样的flexible自身的预设
那么我们将会有预设的dpr,此时flexible将根据我们预设的dpr通过scale=1/dpr的方式来计算出我们的缩放,进而影响layout viewport
的大小

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;
   }

接下来,如果我们既没有通过<meta name="flexible" content="initial-dpr=2" />这种方式预设dpr,
也没有通过<meta name="viewport" content="initial-scale=1">的方式预设缩放,此时flexible开始根据
设备的dpr来动态计算缩放。对于非苹果设备,flexible设置dpr为1,对于苹果设备,iPhone3以下非retina屏,dpr为1
iPhone4-iPhone6为retina屏,dpr为2,iPhone6Plus为retina HD屏,dpr为3,由于flexible是一个专注于移动端
的解决方案,所以平板(包括iPad)或者桌面端的dpr都为1

docEl.setAttribute('data-dpr', 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);
     }
 }

计算完缩放后,将获取的dpr值设置到根元素上,这样我们就可以通过以下方式:

.selector {
    2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

为不同dpr的屏幕设置不同的字体大小,字体之所以不用rem布局,是因为

我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

同时当不存在metaEl时,flexible动态生成一条<meta name="viewport" content="initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale},user-scalable=no">
的标签,如果<html>下存在元素(如<head>等元素)那么,将meta标签插入,如果没有,就将meta标签用一个div包装,然后
通过document.write写入到文档中

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;
   }

好了,缩放和dpr都设置好了,下一步我们要设置根元素的font-size了,这样我们可以通过rem的方式
适配不同屏幕。首先我们需要通过docEl.getBoundingClientRect().width获得layout viewport的宽度,
然后将layout viewport宽度分为10份,1份为1rem。至于设置540px,是为了让在ipad横屏这种情况下浏览页面,不至于因为拉伸适配后体验太差。当然这还是有一点点问题的
因为这样10rem将不会是ipad的满屏了。当然这是移动端解决方案,并没有考虑平板和桌面端

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);

接着当窗口发生变化或者页面重新从缓存中载入时,我们都要重新设置尺寸

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);
   }

body上设置12 * dpr的font-size值,为了重置页面中的字体默认值,不然没有设置font-size的元素会继承html上的font-size,变得很大。

flexible.dpr = win.dpr = dpr;
        flexible.refreshRem = refreshRem;
        flexible.rem2px = function (d ) {
            var val = parseFloat ( d ) * this.rem;
            if ( typeof d === 'string' && d.match ( /rem$/ ) ) {
                val += 'px';
            }
            return val;
        }
        flexible.px2rem = function (d ) {
            var val = parseFloat ( d ) / this.rem;
            if ( typeof d === 'string' && d.match ( /px$/ ) ) {
                val += 'rem';
            }
            return val;
        }

最后,flexible提供了两个工具函数px2rem和rem2px,这里就不在阐述了

总结

看完flexible,实实在在的感受到rem布局的妙处,通过动态设置缩放系数的方式,
让layout viewport与设计图对应,极大地方便了重构,同时也避免了1px的问题,
然而略有遗憾的就是在安卓和ipad上的表现不佳了。

免责声明:文章转载自《libflexible源码阅读》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux静默安装matlabEA(Enterprise Architect) 活动图Activity下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

CSS3系列四(Media Queries移动设备样式)

viewport设置适应移动设备屏幕大小  viewport:允许开发者创建一个虚拟窗口并自定义其窗口的大小或缩放功能 <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0" /> 代码中的content属性可以设置如下6种不同参数...

解决pc端屏幕缩放比例对页面布局的影响

现在很多笔记本电脑都推荐将缩放设置为125%,等比例放大显示。 这对我们前端的页面的布局会产生一些影响 首先,单独的响应式布局hold不住这个问题,因为出问题的是device-pixel-ratio。 问题现象是高分屏下整好的东西,在普分屏下会放大;而普分屏下整好的东西,在高分屏上会缩小。 重现这个问题不需要高分屏,直接用Ctrl++或者Ctrl+-出...

webstorm下的sass自动编译和移动端自适应实践

1、安装Ruby 2、安装sass 3、webstorm配置file watcher 4、移动端自适应 1、安装Ruby   安装Ruby,有多种方式,打开官网下载 因为,使用的是window选择RubyInstall,下载地址 RubyInstall下载地址 选择对应系统的版本,下载完成,安装 添加到path,建议勾上,安装完成后,打开开始面板,...

font-size:0; 消除空白间隙

使用font-size:0解决设置inline-block引起的空白间隙问题 一、空白间隙问题 在进行页面布局的时候为了页面代码所谓整洁刻度,往往会设置缩进或是换行,但是元素display为inline-block或是inline时,行内元素虽然没有设置  margin值,这些换行或是缩进。还是会出现空白间隙。 如下所示: HTML部分 <div i...

webpack 多应用项目搭建

前言: 多应用在实际的项目中使用场景也是比较多的,话不多说,直接进入搭建过程 项目搭建: 请参考之前的webpack项目搭建笔记,此处不再过度讲解,项目结构如下 app1.html 1 <!DOCTYPE html> 2 <html style="font-size:20px"> 3 <head> 4 <...

layui 一行多列控件时使用table布局

当使用多列布局时,使用div+css布局感觉代码不好控制,使用table结构清晰,布局简洁,不用写一堆的css来定位,控制大小的。 例子: <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="w...