webpack实现一个行内样式px转vw的loader示例


Posted in Javascript onSeptember 13, 2018

需求

自从有了postcss来处理css文件,我们可以快速进行网站适配的开发,只需要改改参数,样式按照设计稿的px写,webpack编译自动转换成rem或者vw等。

但是,标签内的px怎么办呢?postcss并不提供转换这个的功能。

探索

启动思路

我正在做一个vue项目,刚好想要实现上面提到的需求,例如下面的例子

<h3 style="font-size: 28px;margin-top: 10px" width="500px">Test</h3>

我希望他能根据我设置的基准值自动转换成vw。

<h3 width="00vw" style="font-size: 00vw; margin-top: 00vw;">Test</h3>

要想实现这样一个东西,离不开编译工具webpack,webpack有loader、plugin,用什么好呢?通过找资料,我从一篇px转rem的文章中得到了提示 react内联样式使用webpack将px转rem

没错,就是webpack-loader

写一个webpack loader,在webpack编译阶段,读取vue文件里面的内容,通过正则识别出需要转换的像素px,再通过公式转换成vw。

开始行动

1、了解loader的实现原理

写一个loader很简单,传入source,干些坏事,干完之后,返回处理过的source。source对应的是每一个通过loader匹配到的文件。

module.exports = function (source) {
 // 干些坏事
 return source
}

2、如何让loader干坏事

先看一个简单的vue文件,通常分为3部分,<template>、<script>、<style>

<template>
 <div>
  <h3 style="font-size: 28px;margin-top: 10px" width="500px">Test</h3>
 </div>
</template>

<script>
 export default {
  name: '',
  components: {},
  created () {},
  mounted () {},
  methods: {}
 }
</script>

<style lang="less">
 h3 {
  font-size: 20px;
 }
</style>

我们知道<style>部分已经有postcss会进行转换处理,所以我把重点放到了<template>内部的 “00px”。

其实source对应的就是这样一个vue文件,该例子中有28px、10px、500px是需要转换的目标,首先用正则把他们都找出来。

先把template部分提出来,防止把style部分也转换了

const template = /<template>([\s\S]+)<\/template>/gi

// 匹配出来的部分
<template>
 <div>
  <h3 style="font-size: 28px;margin-top: 10px" width="500px">Test</h3>
 </div>
</template>

匹配px的正则

const ZPXRegExp = /(\d+)px/

对template里面的px进行转换

module.exports = function (source) {
 let _source = ''
 // 如果当前的source里面存在template
 if (template.test(source)) {
  // 匹配template部分
  _source = source.match(template)[0]
 }
 // 匹配出template里面的px
 let pxGlobalRegExp = new RegExp(ZPXRegExp.source, 'ig')
 if (pxGlobalRegExp.test(_source)) {
  // px转换vw,核心部分
  let $_source = _source.replace(pxGlobalRegExp, createPxReplace(defaults.viewportWidth, defaults.minPixelValue, defaults.unitPrecision, defaults.viewportUnit))
  // 转换之后替换回source中,返回函数值
  return source.replace(template, $_source)
 } else {
  //没有就不转,直接返回
  return source
 }
}

px转vw的公式

我使用的是 postcss-px-to-viewport 内部实现的转换公式

function createPxReplace (viewportSize, minPixelValue, unitPrecision, viewportUnit) {
 // 不用好奇$0, $1是怎么来的,他们是replace第二个参数提供的
 return function ($0, $1) {
  if (!$1) return
  var pixels = parseFloat($1)
  if (pixels <= minPixelValue) return
  return toFixed((pixels / viewportSize * 100), unitPrecision) + viewportUnit
 }
}
function toFixed (number, precision) {
 var multiplier = Math.pow(10, precision + 1),
  wholeNumber = Math.floor(number * multiplier)
 return Math.round(wholeNumber / 10) * 10 / multiplier
}

使用和postcss-px-to-viewport类似的配置

一个基本的配置大概包含这些信息

let defaultsProp = {
 unitToConvert: 'px',
 viewportWidth: 750,
 unitPrecision: 5,
 viewportUnit: 'vw',
 fontViewportUnit: 'vw',
 minPixelValue: 1
}

给webpack-loader加上option

const loaderUtils = require('loader-utils')

const opts = loaderUtils.getOptions(this)
const defaults = Object.assign({}, defaultsProp, opts)

好了,现在我们实现了一个可以干坏事的loader,?不,是做好事!

我们来看看转换成果

<h3 width="66.66667vw" style="font-size: 3.73333vw; margin-top: 1.33333vw;">Test</h3>

反思

虽然实现了我一开始的需求,但是心里总是不淡定,因为还些坑没有想明白,后续如果想明白了,再进行完善。

源码

style-vw-loader

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javaScript 关闭浏览器 (不弹出提示框)
Jan 31 Javascript
html文件中jquery与velocity变量中的$冲突的解决方法
Nov 01 Javascript
浅谈Angularjs link和compile的使用区别
Oct 21 Javascript
JavaScript实现的搜索及高亮显示功能示例
Aug 14 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
Apr 12 Javascript
javascript标准库(js的标准内置对象)总结
May 26 Javascript
浅谈vue首屏加载优化
Jun 28 Javascript
Vue实现双向绑定的原理以及响应式数据的方法
Jul 02 Javascript
JS中比较两个Object数组是否相等方法实例
Nov 11 Javascript
js实现搜索提示框效果
Sep 05 Javascript
Openlayers3实现车辆轨迹回放功能
Sep 29 Javascript
JavaScript实现音乐导航效果
Nov 19 Javascript
vue项目开发中setTimeout等定时器的管理问题
Sep 13 #Javascript
详解react内联样式使用webpack将px转rem
Sep 13 #Javascript
详解webpack 热更新优化
Sep 13 #Javascript
Vue中使用 setTimeout() setInterval()函数的问题
Sep 13 #Javascript
Angularjs之ngModel中的值验证绑定方法
Sep 13 #Javascript
在小程序/mpvue中使用flyio发起网络请求的方法
Sep 13 #Javascript
解决angular2在双向数据绑定时[(ngModel)]无法使用的问题
Sep 13 #Javascript
You might like
Zend Framework中的简单工厂模式 图文
2012/07/10 PHP
PHP mail()函数使用及配置方法
2014/01/14 PHP
PHP命名空间(namespace)原理与用法详解
2019/12/11 PHP
jQuery实现页面滚动时层智能浮动定位实例探讨
2013/03/29 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
2013/06/08 Javascript
JavaScript 学习笔记之操作符(续)
2015/01/14 Javascript
javascript 实现 原路返回
2015/01/21 Javascript
使用Jasmine和Karma对AngularJS页面程序进行测试
2016/03/05 Javascript
使用Object.defineProperty实现简单的js双向绑定
2016/04/15 Javascript
javascript如何定义对象数组
2016/06/07 Javascript
url中的特殊符号有什么含义(推荐)
2016/06/17 Javascript
js 将图片连接转换成base64格式的简单实例
2016/08/10 Javascript
Ubuntu 16.04 64位中搭建Node.js开发环境教程
2016/10/19 Javascript
gulp加批处理(.bat)实现ng多应用一键自动化构建
2017/02/16 Javascript
JS简单实现点击按钮或文字显示遮罩层的方法
2017/04/27 Javascript
详解微信小程序 相对定位和绝对定位
2017/05/11 Javascript
vue-cli+webpack在生成的项目中使用bootstrap实例代码
2017/05/26 Javascript
详解webpack引用jquery(第三方模块)的三种办法
2019/08/21 jQuery
sharp.js安装过程中遇到的问题总结
2020/04/02 Javascript
[48:35]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 TNC vs Optic
2018/04/03 DOTA
python三元运算符实现方法
2013/12/17 Python
Python中Django发送带图片和附件的邮件
2017/03/31 Python
Python基于列表模拟堆栈和队列功能示例
2018/01/05 Python
python使用folium库绘制地图点击框
2018/09/21 Python
django Admin文档生成器使用详解
2019/07/22 Python
Python+Redis实现布隆过滤器
2019/12/08 Python
Python中文分词库jieba,pkusegwg性能准确度比较
2020/02/11 Python
Django基于客户端下载文件实现方法
2020/04/21 Python
Python的轻量级ORM框架peewee使用教程
2021/02/05 Python
Vilebrequin欧洲官网:法国豪华泳装品牌(男士沙滩裤)
2018/04/14 全球购物
西班牙品牌鞋子、服装和配饰在线商店:Esdemarca
2021/02/17 全球购物
如何利用cmp命令比较文件
2016/04/11 面试题
2014预防青少年违法犯罪工作总结
2014/12/10 职场文书
Nginx的反向代理实例详解
2021/03/31 Servers
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL
Java 数组的使用
2022/05/11 Java/Android