postcss是css的babel,js我们可以用babel处理他的ast,最后生成目标代码。css文件我们也可以用postcss来处理文件的ast树,生成目标代码。
本篇文章基于 vite + react postCss
来实现myPxToViewPortPlugin
插件。
初始项目
npx create-vite
app.js
import { useState } from 'react';
import './App.css';
function App() {
const [count, setCount] = useState(0);
return (
<>
<div className="page">
<div className="left"></div>
<div className="right">
测试自适应
</div>
</div>
</>
);
}
export default App;
app.css
.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;
;
}
}
启动
postcss插件的本质就是一个函数
在vite.config.js里面
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
const myPxToViewPortPlugin = () => {
return {
postcssPlugin: 'myPxToViewPortPlugin',
Declaration(node) {
const value = node.value;
console.log('样式值:', value);
}
};
};
export default defineConfig({
plugins: [react()],
css: {
postcss: {
plugins: [myPxToViewPortPlugin()]
}
}
});
测试
实现目标把样式表里面的px换成vw。
用正则表达式搜索 XXpx 数据
'"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)'
插件
const getUnitRegexp = (unit) => {
return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
};
const myPxToViewPortPlugin = () => {
return {
postcssPlugin: 'pxtoVewiport',
Declaration(node) {
const value = node.value;
if (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, '');
}
}
};
};
这里的1280就是我们开发中的设计稿宽度,3是保留的位数。那么继续优化一下,将设计稿宽带和保留位数改为可传参数
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
const getUnitRegexp = (unit) => {
return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
};
const myPxToViewPortPlugin = (viewportSize = 1280, Places = 2) => {
return {
postcssPlugin: 'myPxToViewPortPlugin',
Declaration(node) {
const value = node.value;
if (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: [react()],
css: {
postcss: {
plugins: [myPxToViewPortPlugin()]
}
}
});
如果是手机