postcss 插件实现移动端适配

354 阅读1分钟

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;
    ;
  }
}

启动

image.png

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()]
    }
  }
});

测试

image.png

实现目标把样式表里面的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, '');
      }
    }
  };
};

image.png

image.png

这里的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()]
    }
  }
});

如果是手机

image.png

参考:blog.csdn.net/bxqmz/artic…