🌟前言
目前前端实现移动端适配方案千千万,眼花缭乱各有有缺,但目前来说postcss-px-to-vewiport是一种非常合适的实现方案,postcss-px-to-vewiport是一个基于postCss开发的插件,其原理就是将项目中的px单位转换为vw(视口宽度)。对postCss不了解的朋友可以看看我的上篇文章postCss基本介绍。
🌟实现
本篇文章是使用vite + vue3 基于postCss来实现postcss-px-to-vewiport插件。
1.创建项目
使用vite创建
npm init vite@latest
使用vue脚手架创建
vue create projectname
选自己喜欢的方式创建就OK
2.简单布局
在公司项目开发中,UI会出设计图,会有一个设计稿的宽度,然后我们根据这个宽度去适配,假设我们现在设计稿的宽度是1280,那么我们写出下面的简单布局:
App.vue文件:
<template><div class="page"><div class="left"></div><div class="right">测试自适应</div></div>
</template><style scoped>
.page{width: 1276px;height: 748px;display: flex;border: 2px red solid;.left{width: 600px;height: 300px;background-color: cadetblue;}.right{width: 300px;height: 300px;margin-left: 200px;background-color: #425e5e;font-size: 20px;;}
}
</style>
可以看到,当页面宽度是1280时,我们上面写的代码是没有问题的,那这时候我们修改页面大小效果如下:
明显不是我们想要的效果,那么开搞。
3.编写插件
vite中是自带postCss的,我们不需要额外安装,在vite.config.ts文件中如下:
export default defineConfig({plugins: [vue()],server: {host: '0.0.0.0', //默认情况是不能用ip访问port: 3000},css: {postcss: {plugins: []}}
})
plugins数组中就是填写需要使用的插件。下面我们编辑pxtoVewiport方法:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'const pxtoVewiport = (): Plugin => {return {postcssPlugin:'pxtoVewiport',Declaration(node){const value = node.valueconsole.log('样式值:',value)}}
}
export default defineConfig({plugins: [vue()],server: {host: '0.0.0.0', //默认情况是不能用ip访问port: 3000},css: {postcss: {plugins: [pxtoVewiport()]}}
})
此时可以看到打印的信息:
也就是说我们已经拿到项目中的所有样式值,那么接下来我们就是要把所有px单位改成vw。
这里我原本自己写正则实现后,发现还会有margin: 20px 60px;这样的情况,裂开,正则太烧脑,使用程序员必备技能,CV大法,看看postcss-px-to-vewiport源码是怎么实现的,然后就拿到了这个正则:
'"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)'
ok,能用就行,那接下来就是替换过程:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'const getUnitRegexp = (unit: string) => {return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
}const pxtoVewiport = (): Plugin => {return {postcssPlugin:'pxtoVewiport',Declaration(node){const value = node.valueif (value.includes('px')) {const pxRegexp = getUnitRegexp('px')node.value = node.value.replace(pxRegexp, (match) => {return match.replace(/(\d*\.?\d+)/g, (m) => {return (parseFloat(m) / 1280 * 100).toFixed(3) + 'vw'})})let reg = new RegExp(/px/,'ig') //在这儿把px删掉node.value = node.value.replace(reg,'')}}}
}export default defineConfig({plugins: [vue()],server: {host: '0.0.0.0', //默认情况是不能用ip访问port: 3000},css: {postcss: {plugins: [pxtoVewiport()]}}
})
跑起项目:
这时候单位都转换成了vw,在各种大小的屏幕都是我们想看到的效果了。
继续看代码
这里的1280就是我们开发中的设计稿宽度,3是保留的位数。那么继续优化一下,将设计稿宽带和保留位数改为可传参数:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'const getUnitRegexp = (unit: string) => {return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
}
const pxtoVewiport = (viewportSize = 375,Places = 2): Plugin => {return {postcssPlugin:'pxtoVewiport',Declaration(node){const value = node.valueif (value.includes('px')) {const pxRegexp = getUnitRegexp('px')node.value = node.value.replace(pxRegexp, (match) => {return match.replace(/(\d*\.?\d+)/g, (m) => {return (parseFloat(m) / viewportSize * 100).toFixed(Places) + 'vw'})})let reg = new RegExp(/px/,'ig') //在这儿把px删掉node.value = node.value.replace(reg,'')}}}
}
export default defineConfig({plugins: [vue()],server: {host: '0.0.0.0', //默认情况是不能用ip访问port: 3000},css: {postcss: {plugins: [pxtoVewiport(1280,3)]}}
})
到里就完成了一个移动端适配的小插件。
🌟总结
基于postCss还可以做很多事情,postCss就是css界的babel,我们这里也是基本实现了postcss-px-to-vewiport插件的功能。后续还可以继续改进。