本文以px2rpx-loader的源码为学习对象,了解其工作机制以及loader封装的思想。

1.前言

最近在了解mpvue框架的时候,对于其能够实现一套代码兼容web和微信小程序(以下简称小程序)的能力十分着迷,虽然小程序的MINA框架有着Vue的影子,但是无口否认的,小程序做了很多有着自己风格的封装,如rpx单位,WXML中的 view, button, text等标签,与web有着较多的差异。

px2rpx-loader作为支持mpvue实现兼容web和小程序的设施之一,有一定值得我们学习的地方。

2.rpx介绍

对于rpx的概念和作用,此处引用微信官方的话说,就是“在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可”。

rpx可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx。

rpx的确很好用,大大减轻了开发者对于兼容不同设备的工作量,虽然现在有很多移动端设备兼容的方案,如阿里的flexible,但是小程序中用一个单位就能解决这个恼人的问题,也是极好的。

3.px2rpx-loader的使用

让我们回到实际业务中,假设现在设计师以iphoneX的尺寸为基础,出了一套1125px * 2436px的设计图,并且已经完成了以px单位为基础的web移动端页面的还原,现在需要将已经完成了的页面迁移到小程序中,因此需要解决宽高的转换和单位的转换,我们接下来通过一个测试项目对px2rpx-loader的使用进行介绍。

px2rpx-loader可以依靠webpack来实现,过程如下:

( 1 ) npm install px2rpx-loader // 在目标文件夹中安装loader包

( 2 ) 在webpack.config.js中进行相应配置

{ test: /\.css$/,use: ['style-loader','css-loader','px2rpx-loader?rpxUnit=1.5' // px转换为rpx的配置,rpxUnit=1.5为配置参数,后面会介绍] }
复制代码

根据该配置,在webpack进行打包的时候就会对src目录下的 index.css 文件进行预处理。

( 3 ) 此外,我们需要简单写一下index.html和index.css的测试代码

index.html

<body><div
class=“container”></div><script
type="text/javascript"
src="./dist/bundle.js"></script></body>
复制代码

index.css

.container {width: 1125px;height: 2436px;background-color: pink;}
复制代码

( 4 ) 在控制台中通过webpack命令进行打包

$ webpack

最后可以在浏览器调试窗口中看到(之所以被线划掉,是因为浏览器不支持rpx单位的)

此时单位已经转换完成,并且也根据比例调整为750rpx宽,此时的类为container的div元素可以在小程序中适应各个尺寸的设备了(当然在小程序中是没有div标签的,最终的实现还需要mpvue-loader将div标签转换为小程序中的view标签)。

4.px2rpx-loader源码解析

从上面的一个测试中可以看出,其实px2rpx-loader实现的功能并不复杂,主要实现了两个转换:

( 1 ) 将宽度的数字部分按比例缩小

( 2 ) 将px单位改成rpx单位

功能虽然简单,但我们也不妨了解其内部实现的原理,让我们学习封装loader的一些思想。

loader中第一个解决的问题是获取到webpack.config.js中的配置参数,可以借助loaderUtils模块实现。

var loaderUtils
= require('loader-utils')   // 获取loader的配置项var options =
loaderUtils.getOptions(this) // 获取如上文webpack配置中,'px2rpx-loader?rpxUnit=1.5’中的rpxUnit=1.5
复制代码

然后,loader中应该预设好默认的配置,这样在使用loader时就可以只写部分配置或者直接使用默认配置,这里借助了extend模块实现。

var extend = require('extend'); // 用于克隆对象var defaultConfig = { … }; // 默认配置项var config = { };extend(this.config, defaultConfig,
options);// 在后面进行单位转换的函数中,将config变量作为实参传入,进行相应的处理
复制代码

extend模块是用来克隆(或者叫做拓展)多个对象的,熟悉jQuery的朋友应该都知道$.extend() 方法,其接受多个对象作为参数,以参数中第一个对象为目标,将参数中其他对象合并到目标对象上,如果第一个参数为true,那么就会实现深克隆。

loader需要处理的对象的是css代码,但是css代码并不是JS能够直接能够进行逻辑处理的对象,因此需要使用css模块进行css代码到css AST(css抽象语法树)的转换,这是loader中关键的一步

var astObj = css.parse(cssText); // 解析css文件,构建css AST树,cssText形参由webpack将css代码作为实参传入

经过转换后,css代码会被转换为JSON格式的对象,举个例子:

//CSS代码

body {background: #eee;color: #888;}//CSS AST{"type":
"rule","selectors": ["body"],"declarations": [{"type":
"declaration","property":
"background","value":
"#eee","position": {"start": {"line": 2,"column": 3},"end": {"line": 2,"column": 19}}},{"type":
"declaration","property":
"color","value":
"#888","position": {"start": {"line": 3,"column": 3},"end": {"line": 3,"column": 14}}}]}
复制代码

在这个JSON对象中,记录了代码的位置(line, column),样式的属性名(property)和属性值(value),样式的类型(type),选择器(selectors)等,通过这个JSON对象,可以很轻易的通过JS实现单位转换了。

但是需要考虑到一个问题,即在一个css文件中,可能并不需要把所有的px都转换为rpx,如字体大小,不应该随着屏幕尺寸的增大而过度增大。所以load中允许通过一个特殊的注释“ /*px*/ ”来进行标记,表明当前的样式不需要转换。以之前的例子举例,我们在index.css中添加一个/*px*/注释,表示height: 2436px; 这个属性不需要转换。

index.css

.container {width: 1125px;height: 2436px; /*px*/background-color: pink;}
复制代码

最后可以在浏览器调试窗口中看到结果不出所料,高度部分的样式没有被转换。

单位转换的逻辑很简单,只需要遍历css AST的JSON对象,将没有“ /*px*/ ”标记的样式代码进行数值部分的转换,然后再拼接上“rpx”单位即可。

function _getCalcValue (value, config) { value即JSON中样式属性值,config即上文所说整合过的配置参数var pxRegExp =
/\b(\d+(\.\d+)?)px\b/; // 用来匹配形如“ 24.55px ”的正则function getValue(val) {return val == 0 ? val : val +
‘rpx’; // 将转换后的数值拼接上’rpx’单位}return value.replace(pxRegExp,
function ($0, $1) {return getValue($1 /
config.rpxUnit); // 数值部分按比例转换});};
复制代码

5.loader封装思路整理

下图对整个loader的思路做一个整理:

整个过程大致可以分为3部分,一是对配置参数的获取和整合,二是css代码和css AST的相互转换,三是px单位到rpx单位的处理。举一反三,我们不难想象出,其他的一些css预处理包也应该是遵循着相似的逻辑来进行,譬如px转为rem,rem转为rpx,或者是px转vw等等。

通过深入了解px2rpx-loader,我们总结了其封装的思路,顺带学习了一下css的抽象语法树。在后面的工作或者学习中,我们也是可以尝试封装自己的loader,来进行一些兼容和减少我们重复性的操作的。

基于px2rpx-loader,探讨一下loader的封装思想相关推荐

  1. root cause java.lang.LinkageError: loader constraint violation: loader (instanc

    用Jstl开发,遇到问题: root cause java.lang.LinkageError: loader constraint violation: loader (instance of or ...

  2. 基于JavaSDK实现微信支付,springboot封装签名过程,直接调用controller层实现调起微信支付接口

    微信小程序实现微信支付需要繁杂的过程,各种接口调来调去,对于小白来说是一个比较复杂的过程.下方 开源项目 是对微信 javaSDK 的进一步封装.主要对service层和controller层进行了封 ...

  3. android sqlite 操作类封装,SQLiteUtils 一个简单的基于 Android 的 Sqlite 数据库的操作封装库 @codeKK Android开源站...

    一个简单的基于 Android 的 Sqlite 数据库的操作封装,它有如下的好处: 便捷地创建表和增添表字段 通过操作对象来 insert 或者 update 表记录 支持多种查询方式,支持分页查询 ...

  4. 基于 FPGA Vivado 的74系列IP封装(附源工程)

    今天给大侠带来基于 FPGA Vivado 的 74 系列IP封装,开发板使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833.话不多 ...

  5. GSF基于PHP Swoole Framework进行二次封装

    基于Swoole框架的封装扩展和完善,Swoole由于其文档太少,难度对于PHP程序员来说过于大,很多php程序员敬而远之. 工作之余基于Swoole frame 进行了二次封装,不断完善中 暂时定名 ...

  6. vue横向树结构_基于vue.js实现树形表格的封装

    基于vue.js实现树形表格的封装(vue-tree-table) 前言由于公司产品(基于vue.js)需要,要实现一个树形表格的功能,百度.google找了一通,并没有发现很靠谱的,也不是很灵活.所 ...

  7. Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/catal

    主要因素: Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache ...

  8. BaseActivity 的封装思想

    有人说现在流行的是mvp架构的程序,但我想问你,mvp架构的目的是什么呢? 他就是为了让代码的阅读性和可拓展性更强,同样,我写这篇博客的目的也是,而且我认为,在一些界面,根本就没必要使用mvp架构,架 ...

  9. BaseActivity的封装思想及YzsBaseActivity详解

    本人最新公众号<Android百科全书>,汇集了各个公众号的优秀文章,进行分类整理,让大家能够更方便的查阅,希望大家多多支持,来个关注奥. BaseActivity在我们的项目中非常常用, ...

最新文章

  1. 一文掌握Conda软件安装:虚拟环境、软件通道、加速solving、跨服务器迁移
  2. SQL Server 查询性能优化——堆表、碎片与索引(一)
  3. Future获取线程返回值能使线程顺序执行?
  4. 云计算产业被市场广泛看好 未来市场规模达4300亿元
  5. 添加与编辑共用一个jsp页面时,控制按钮的显示与隐藏
  6. 初学Java开发,这9本书值得一看
  7. 自动化办公之excel教程(3):数据编辑操作,表格的美化操作,应用表格样式和单元格样式,制作报销汇总单
  8. 理解云计算备份与灾难恢复
  9. 使用PXE+VNC方式安装CentOS 7
  10. vs python opencv_VsCode+Anaconda+OpenCV开发环境搭建
  11. Python random 模块 - Python零基础入门教程
  12. python列索引行的数据公式_用列和行索引函数填充dataframe缺失元素的最有效方法...
  13. vue 获取id元素,vue.js怎么获取dom元素?
  14. range 小程序picker_小程序开发讲义【入门篇】 03
  15. adb查看手机设备型号、品牌、机型等信息
  16. kon-boot启动盘测试
  17. html怎么制作扇形,css3绘制画圆、扇形
  18. 计算机无法找到扫描仪和照相机,我的电脑不显示扫描仪和摄像头的原因及解决方法...
  19. zuk android os 流量,国产机首发? ZUK Z1或12月推送安卓6.0
  20. linux定时任务输出时间日志,linux 定时任务 日志记录

热门文章

  1. SAP SD基础知识之交货中的控制元素
  2. 京东和小米正在使用AI取代人工客服 | 海斌访谈
  3. IBM认为将AI用于人力资源的价值
  4. 一文读懂机器学习项目的完整生命周期
  5. 一文区分什么是「过拟合」和「欠拟合」?
  6. 干货回顾丨TensorFlow四种Cross Entropy算法的实现和应用
  7. 心得丨一位资深程序员大牛给予Java初学者的学习路线建议
  8. 诺奖得主被曝40多篇论文造假!
  9. 一文拆解中国火星车着陆全过程
  10. 震撼!15项世界互联网领先科技成果发布,将对你的生活产生什么影响?