因项目的需求,本身动手写了一个 PostCSS 插件 postcss-px2vw,主要用于将 px
转成 vw
和 rem
,rem
做为回退模式。也恰好借此机会总结一下 npm
包的发布流程,文章还会介绍到七牛云图片的使用与上传相关的技巧,以及期间遇到的一些问题。css
转换 px
单位的插件有不少,知名的有 postcss-px-to-viewport 和 postcss-pxtorem,前者是将 px
转成 vw
,后者是将 px
转成 rem
。html
起初是看了大漠的一篇文章《如何在Vue项目中使用vw实现移动端适配》,因而怀着激动的心情,就在项目中也使用 vw
来作移动端的适配。该文章大力推行用 vw
代替 rem
作适配,在amfe-flexible 项目文档中也推荐 vw
的替代方案。可是考虑到移动端对 vw
的支持状况不如 rem
,因此仍有不少项目都选择使用 rem
来布局。因而就想到将 rem
做为一种回退机制,或许以为不必,直接放弃 vw
使用 rem
不就完了?确实,不过既然是折腾,也就不须要那么多理由了,其实饿了么平台就用了此方案。前端
关于移动端适配方案,也有一些我的的亲身体会,有时间另启一篇文章详细总结一下。vue
首先,得提一下 CSS 样式的回退原理:当 CSS 遇到没法识别的一些样式时,不会报错,而是忽略它。而且后面的样式声明比前面的样式声明权重要高(也就是会覆盖前面的样式)。因此,咱们要达到的效果是这样的:node
.class {
margin-top: 2rem;
margin-top: 20vw;
}
复制代码
浏览器会优先使用第二个 margin-top: 20vw;
,若是不支持该声明就会直接忽略它,并使用第一个 margin-top: 2rem;
。git
要实现这样的效果,一开始想到的是同时使用上面介绍到的两款插件,设置 postcss-pxtorem 的参数 replace: false
,最后的结果是这样的:程序员
.class {
margin-top: 20vw;
margin-top: 2rem;
}
复制代码
虽然最后结果同时保留了两种单位,可是优先使用的是 rem
,这并不能知足咱们的需求。缘由也很简单,看 postcss-pxtorem
源码就会知道,设置 replace: false
时,它会在当前样式下面插入转换后的结果。而 postcss-px-to-viewport
是不能设置 replace
的,因此,不管如何配置,rem
单位始终会在 vw
的下面。github
基于这个点,就能够编写咱们本身的代码了。算法
打开 postcss-px-to-viewport 源码,其实也就短短的几十行代码。就算没写过 PostCSS 插件,看到源码,依葫芦画瓢,也能写一个适合本身的插件来。这是修改事后的源码:npm
'use strict';
var postcss = require('postcss');
var objectAssign = require('object-assign');
module.exports = postcss.plugin('postcss-px2vw', function (options) {
var opts = objectAssign({
viewportWidth: 750,
unitPrecision: 5,
rootValue: 75,
minPixelValue: 1
}, options);
var pxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)px/ig;
return function (css) {
css.walkDecls(function (decl, i) {
if (decl.value.indexOf('px') === -1) return;
var value = decl.value;
if (opts.viewportWidth) {
var pxReplaceForVw = createPxReplace(opts.viewportWidth / 100, opts.minPixelValue, opts.unitPrecision, 'vw');
decl.value = value.replace(pxRegex, pxReplaceForVw);
}
if (opts.rootValue) {
var pxReplaceForRem = createPxReplace(opts.rootValue, opts.minPixelValue, opts.unitPrecision, 'rem');
if (opts.viewportWidth) {
decl.parent.insertBefore(i, decl.clone({
value: value.replace(pxRegex, pxReplaceForRem)
}));
} else {
decl.value = value.replace(pxRegex, pxReplaceForRem);
}
}
});
};
});
function createPxReplace(perRatio, minPixelValue, unitPrecision, unit) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels <= minPixelValue) return m;
return toFixed((pixels / perRatio), unitPrecision) + unit;
};
}
function toFixed(number, precision) {
var multiplier = Math.pow(10, precision + 1);
var wholeNumber = Math.floor(number * multiplier);
return Math.round(wholeNumber / 10) * 10 / multiplier;
}
复制代码
合并了两款插件的核心转换功能,并去掉了一些不经常使用的功能和配置项,实现最初的目的就行,尽可能保持简单易用的原则。该插件只保留了 4 个可配置参数(viewportWidth
、rootValue
、unitPrecision
、minPixelValue
),具体使用说明可查看 项目的README.md 文档。
原本只是为了项目的须要,没打算从项目中独立出现来的。一方面为了熟悉一下 npm 的发布流程,另外一方面也是为了在本身的 github 仓库中保留一份记录。
整个流程很简单,也就几步:
npm init
,填写相关参数说明;npm login
,输入用户名密码以及邮箱。若是没有帐号就去 npm官网 注册一个;npm publish
,大功告成。不过现实每每没有理论那么容易,总会遇到一些问题。
nrm
的话,只需 nrm use npm
便可;package.json
中的 name
不能与仓库中已有的项目重名。若是难以命名,可添加用户名前缀,如:@moohng/postcss-px2vw
。添加用户前缀是不能直接 publish
到公有仓库中的,须要使用 npm publish --access=public
;package.json
中的版本号。为何会使用到七牛云?这本是八竿子也打不着的东西。其实,也就是为了学别人在项目的 README.md
文档最后贴一张我的的收款二维码。先别想其余,就贴一张图自己而言,其实很简单,就是在 markdown
语法中插入一张图片连接地址。
为了一张图片的连接地址,就把七牛云也整一遍?的确,就是出于这个目的因而就研究了一遍七牛云这东西。简单的上传无外乎就是登录到七牛云平台,而后拽一张图片上去,连接地址就有了。但是,做为一个高大上的程序猿,怎能如此将就,固然得有一套不一样寻常的方式了。
最终要达到的效果就是获得一张上传图片的连接地址:static.moohng.com/FrEihC8JSWM… + 图片hash值。
要配置自定义域名,首先得拥有一个已经备案过的域名。而后在七牛云的融合CDN菜单下能够添加域名:
因掘金对图片强制须要使用 https 连接,因此就不配图了。其中要注意的一点就是源站配置必定要选择七牛云存储和对应的存储空间名称。
接下来在域名管理平台配置 CNAME,CNAME 值可在刚添加的域名下查看。如此一来,之后访问七牛云上的资源就能够直接经过自定义域名来访问了。
实现上传最关键的就是要有一个 token,token 的生成在官方文档中都有说明。不过咱们不用本身写算法,官网已经用多种语言实现了封装。前端可参考Node.js SDK,简单实现:
新建一个项目 demo,初始化 npm init
,而后安装七牛云SDK npm install qiniu
。
// index.js
var qiniu = require('qiniu');
// 可在七牛云查看
var accessKey = 'accessKey';
var secretKey = 'secretKey';
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
var options = {
scope: 'moohng', // 存储空间名称
};
var putPolicy = new qiniu.rs.PutPolicy(options);
var uploadToken = putPolicy.uploadToken(mac);
console.log(uploadToken);
复制代码
其中,accessKey
和 secretKey
可在七牛云我的中心查看。
在 Nodejs 环境下运行代码,node index.js
,获得 token。
上传地址可在七牛云开发者中心查看,不一样地区的地址不同。例如,华南地区:http(s)://upload-z2.qiniup.com。
原本是想写一个图形化界面,用来上传图片。无赖本身比较懒,既然拿到了最关键的 token,也有了上传地址,至于图形化界面有时间再说吧。
做为程序员,逼格最高的莫过于命令行了。因而,就想到了 Linux 下经常使用的 curl
命令。
$ curl http://upload-z2.qiniup.com -F "file=@./img_example.png" -F "token=这里是生成的token"
复制代码
而后一个优雅的回车,一切就结束了!不出意外会返回一个 key
,这个 key
拼接上以前自定义的域名,就能够随心所欲了。
关于 curl 命令,-F 表示上传文件,文件参数与其余参数必须分开写,文件参数使用 @+文件路径。
更多的使用说明及相关参数请参考七牛云开发文档。
七牛云提供了多个图片处理工具,裁剪、缩放、压缩等。若是放到 github 上的图片太大,可能会加载不出来,因此,对图片进行缩放和压缩是颇有必要的。
处理以前:static.moohng.com/FrEihC8JSWM… (85.1k)
处理以后:static.moohng.com/FrEihC8JSWM… (17.1k)
其效果仍是很明显的。
关注我,不按期更新前端技术型文章。