因为平时工作中开发h5网页的时候,为了更好适配不同的尺寸, 常常会应用vw单位, 通常是通过 vw = 元素尺寸 / 设计图屏幕尺寸 , 比方一个元素在 37.5px的设计图下宽 100px, 那失去的 vw就是 37.5 / 375 * 100 = 10vw, 每次都须要这样去计算又特地麻烦, 所想把这个事件给自动化

postcss

postcss 会将 css转换为 ast, 并提供了运行插件的机制, 这么一看和babel 很像,只是解决的对象不同, 一个是js ,一个是css, 如果你对ast 或者 babel 的概念不分明,举荐看看之前的这篇文章 保姆级教学!这次肯定学会babel插件开发!

css 的 ast 在哪里查看呢, 到这个网站 https://astexplorer.net/, 将下面两个配置改成css和postcss即可

思路整顿

写代码前思考环节是很重要的, 咱们的目标有一下几点:

  1. 为了不影响老我的项目的px应用或者是一些必须px的中央, 咱们不能暴力的针对所有px值进行转换
  2. 可能灵便设置屏幕尺寸, 保留小数点位数等等

那思考一下该如何一步步来做:

  1. 通过ast 拜访,咱们要匹配出例如 width: 300px,这样的值,取出 300 通过计算的出 vw的值, 并将px改为 vw
  2. 须要有一个标识符,咱们好针对某些须要转换的px 进行解决, 其余的不进行解决, 这里我默认应用 width: '%300px' , 格调进行书写, 这里须要写成字符串(因为编辑器会报错)
  3. 容许动静传入参数
  4. 比方计算结果为 width: 80.00vw 的整数应该主动去掉小数点变为 width: 80vw , 减小体积

入手开发

因为公司应用的是postcss 7.x系列, 所以我这边应用7.x 系列的插件语法进行书写(8版本以上的插件注册有一点点不一样, 不过一通百通不影响)

先来看看如果咱们什么逻辑都不写,最根本的一个插件应该如何去写

module.exports = postcss.plugin('plugin-name', option => {     return (root, result) => {        // 在这里通过 root 操作 ast     }})

晓得了插件的根本模版, 那咱们如何操作ast呢,postcss给咱们定义了是这样几个类型

  • Root: PostCss解决过的Css,整个处理过程基本上都在围绕着Root,Commont,AtRule,Rule都是它的子节点。
  • AtRule: 为带@标识的局部,name为标识名称,params为标识参数。nodes为外部蕴含的其余子节点,能够是Commont,AtRule,Rule,这让咱们能够自定义更多的规定
  • Rule: 选择器款式局部,一个选择器代表一个Rule,选择器对应的款式列表nodes为Declaration构造函数
  • Declaration: 为Css款式属性,prop为款式属性,value为款式值。可给Rule手动增加款式属性,也能够批改prop,value。

针对这些个类型, 文档中给咱们提供了找到这些类型节点的办法如下, 具体可查看文档, 地址: postcss:

  • walk
  • walkAtRules
  • walkComments
  • walkDecls
  • walkRules

那咱们应该用哪个来实现咱们的性能呢, 这时候,astexplorer 网站的作用就体现进去了, 咱们能够先将须要解决的css在下面生成ast进行查看,

能够看到,咱们的 width: 300px 在一个 decl 节点里, 并且外层还有一个 rule , 这个 rule 就是叫.demo 的class

那我晓得了, 接下来我是不是只须要解决 decl节点就行了。

来试一下

walkDecls 接管一个回调, 回调内会接管到 postcss给咱们的 decl节点, 咱们通过 正则将合乎咱们规定的value匹配进去, 计算后并将其改写

const postcss = require('postcss')module.exports = postcss.plugin('PLUGIN_NAME', function (opts) {  opts = opts || {}  return function (root, result) {    root.walkDecls(decl => {      // decl.value 就是上图ast内的 300px      // 匹配出 '%300px' / '%-300px' 这样的值再进行解决,      if( /\'%-?(\d+)px\'/.test(decl.value) ) {        decl.value = decl.value.replace(/\'%-?(\d+)px\'/g, (matchStr) => {          // 从 '%300px' 中提出去 300           const numberPx = matchStr.match(/-?\d+/g)          // 设计图尺寸 375,先写死前面通过参数传入          const toVw = (numberPx[0] / 375 * 100).toFixed(2)          // 用+是为了 让 80.00 这种数字变成 80          return +toVw + 'vw'        })      }    })  }})

咱们想方法运行一下咱们书写的插件,这里我用的是vue-cli, 是在vue.config.js 中进行如下配置,

module.exports = { css: {    loaderOptions: {      postcss: {        plugins: [          // 咱们刚刚编写的插件文件名          require('./test.postcss.js')({            // 这里写参数          })        ]      }    }  }},

如果你的我的项目不是vue-cli 书写在 postcss.config.js也是同理, require 引入就行

查看一下执行后果

/* 解决前 */.demo {  width: '%300px';  height: 400px;  left: '%10px';  border: '%-1px' solid black;}/* 解决后 */.demo {  width: 80vw;  height: 400px;  left: 2.67vw;  border: -0.27vw solid black;}

ok 胜利了

而后咱们想方法将其变得灵便可配置
定义三个参数

  • screen 设计图屏幕宽度, 默认375
  • toFixed 小数点保留位数, 默认 2
  • identifier 标识符 默认 '%'

咱们来革新一下代码,如下:

const postcss = require('postcss')module.exports = postcss.plugin('PLUGIN_NAME', function (opts) {  opts = opts || {}  const _screen = opts.screen || 375  const _toFixed = opts.toFixed || 2  const _identifier = opts.identifier || '%'  const vwRgx = new RegExp(`\\'${_identifier}-?(\\d+)px\\'`, 'g')  return function (root, result) {    root.walkDecls(decl => {      if( vwRgx.test(decl.value) ) {        decl.value = decl.value.replace(vwRgx, (matchStr) => {          const numberPx = matchStr.match(/-?\d+/g)          const toVw = (numberPx[0] / _screen * 100).toFixed(_toFixed)          return +toVw + 'vw'        })      }    })  }})

测试一下:

插件参数如下

plugins: [  require('./test.postcss.js')({    screen: 750,    toFixed: 4,    identifier: 'vw'  })]

查看一下执行后果

/* 解决前 */.demo {  width: 'vw300px';  height: 400px;  left: 'vw10px';  border: 'vw-1px' solid black;}/* 解决后 */.demo {  width: 40vw;  height: 400px;  left: 1.3333vw;  border: -0.1333vw solid black;}

这样咱们的插件基本功能就实现实现了, 前面还有针对 @media 媒体查问单位的解决, 也是一样的就不过多论述了,有趣味的而已到github查看残缺代码, 代码已上传 github , 欢送star

插件的话也公布到了npm仓库 ,能够下载 postcss-px2vm 进行应用