基于px2rpx-loader,探讨一下loader的封装思想
本文以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的封装思想的更多相关文章
- axios基于常见业务场景的二次封装
axios axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中.在前端框架中的应用也是特别广泛,不管是vue还是react,都有很多项目用axios作为网络 ...
- 基于小程序请求接口 wx.request 封装的类 axios 请求
基于小程序请求接口 wx.request 封装的类 axios 请求 Introduction wx.request 的配置.axios 的调用方式 源码戳我 feature 支持 wx.reques ...
- 基于SqlSugar的数据库访问处理的封装,支持.net FrameWork和.net core的项目调用
由于我们有时候需要在基于.net framework的项目上使用(如Winform端应用),有时候有需要在.net core的项目上使用(如.net core的WebAPI),那么我们把基于SQLSu ...
- 基于SqlSugar的数据库访问处理的封装,在.net6框架的Web API上开发应用
我前面几篇随笔介绍了关于几篇关于SqlSugar的基础封装,已经可以直接应用在Winform项目开发上,并且基础接口也通过了单元测试,同时测试通过了一些Winform功能页面:本篇随笔继续深化应用开发 ...
- 基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用
在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于El ...
- java基础:详解类和对象,类和对象的应用,封装思想,构造方法详解,附练习案列
1. 类和对象 面向对象和面向过程的思想对比 : 面向过程 :是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的 面向对象 :是一种以对象为中心的编程思想,通过指挥对象实现具体的功能 1. ...
- jquery中ajax中post方法(多学习:洞悉原理,触类旁通)(函数封装思想)
jquery中ajax中post方法(多学习:洞悉原理,触类旁通)(函数封装思想) 一.总结 1.多看学习视频:洞悉原理,触类旁通, 2.函数封装:$.post(URL,data,callback); ...
- openswan中out_sa()函数报文封装思想
out_sa()函数报文封装思想讲解 1. out_sa前言 我已经在上一篇文章中将in_struct函数的基本原理进行了阐述,而out_struct()的实现基本是相同的,如果能理解in_struc ...
- 基于JQuery EasyUI的WebMVC控件封装(含源码)
JQuery EasyUI类库,大家不会陌生,出来已经有很多年了.个人感觉还是很好用的,作者更新频率也很快,bug也及时修复. 最近在整理以前的代码,找到了这个组件,它是将EasyUI组件封装成MVC ...
随机推荐
- C++学习之构造函数和析构函数及指针
C++的构造函数在创建对象时调用,分配内存空间,多少个对象(对象数组)就调用几次构造函数:析构函数在调用结束时调用(可以添加一些最后的处理)以释放内存给其它来用.对于同类型同生命期的对象,先创建的对象 ...
- checkbox多选、全选js效果
//全选checkbox function allCheck() { //全选input var all = $("input[name='all']"); //全部的input ...
- (转)AIX 5.3安装SSH .
AIX 5.3安装SSH . 原文:http://blog.csdn.net/chunhua_love/article/details/12004845 环境:OS:AIX 5.3SSH: opens ...
- 搭建mysql集群,使用Percona XtraDB Cluster搭建
Percona XtraDB Cluster提供的特性有:1.同步复制,事务要么在所有节点提交或不提交.2.多主复制,可以在任意节点进行写操作.3.在从服务器上并行应用事件,真正意义上的并行复制.4. ...
- Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释
遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题a,什么叫序列化和反序列化b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化c,seria ...
- angularjs ui-grid如何动态设置行高
自己开发的公众号,可以领取淘宝内部优惠券 在用ui-grid的时候我们可以用rowHeight设置行高,可是每一行的高度都是一样的,无法根据行内的内容进行自适应.如下图 为了解决这个问题,google ...
- ASP .NET 404 Not Found fontawesome-webfont.woff?v=4.0.3
解决Web部署 svg/woff/woff2字体 404错误最近项目中用到了fontawesome-webfont.svg等字体.部署项目后,发现没有<,+等符号,字体也不对,发现浏览器总是报找 ...
- [转]一次使用Eclipse Memory Analyzer分析Tomcat内存溢出
一次使用Eclipse Memory Analyzer分析Tomcat内存溢出 前言 在平时开发.测试过程中.甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序 ...
- React 内部属性与函数
constructor 构造函数,在创建组件的时候调用一次. 例子: class TodoList extends React.Component { constructor(props, conte ...
- Android开发从系统图库中选择一张图片的方法
刚开始学习OpenCv4Android编程,做了个小demo. 就是一个主界面上添加一个ImageView 两个Button控件. 一个Button用来从系统相册选择一张照片: 另一个Button是用 ...