react 使用 postcss-px-to-viewport 实现 px 自动转 vw 自适应

最近做了一个 react + next 的网址大全项目,需要实现不管是大屏还是小屏,都能让整个页面在一页中显示而不出现滚动条,一顿操作后还是有点小瑕疵,大佬给我推荐了一个插件:postcss-px-to-viewport,试了一下,确实好用,记录一下。

一、安装 postcss-px-to-viewport

bash 复制代码
pnpm install postcss postcss-px-to-viewport --save-dev

安装完后,可以看到我们的项目依赖中多了一行

二、在项目根目录创建 postcss.config.js 文件

键入以下内容

javascript 复制代码
module.exports = {
  plugins: {
    'postcss-import': {}, // 必须放在第一个
    'postcss-px-to-viewport': {
      viewportWidth: 1920,
      unitPrecision: 5,
      viewportUnit: 'vw',
      selectorBlackList: [],
      minPixelValue: 1,
      mediaQuery: false
    },
  }
}

三、修改 next.config.ts 文件

javascript 复制代码
import type { NextConfig } from 'next';
import { join, resolve } from 'path';

const nextConfig: NextConfig = {
  output: 'export',
  distDir: 'build',
  // 使用相对路径前缀,确保静态资源可以正确加载
  assetPrefix: './',
  images: {
    unoptimized: true,
  },
  outputFileTracingRoot: process.cwd(),
  experimental: {
    optimizeCss: false
  },

  webpack: (config, { isServer }) => {
    // 配置 CSS 输出路径
    if (!isServer) {
      const miniCssExtractPlugin = config.plugins.find(
        (p: { constructor: { name: string; }; }) => p.constructor.name === 'MiniCssExtractPlugin'
      );
      if (miniCssExtractPlugin) {
        (miniCssExtractPlugin as any).options.filename = 'static/css/[name].[contenthash].css';
        (miniCssExtractPlugin as any).options.chunkFilename = 'static/css/[name].[contenthash].css';
      }
    }

    // 配置 manifest 文件输出路径
    config.plugins.push(
      new (require('webpack').DefinePlugin)({
        'process.env.MANIFEST_OUTPUT_PATH': JSON.stringify(
          resolve(__dirname, 'build/_next/static')
        )
      })
    );

    // 配置图片和其他资源的输出路径
    config.module.rules.forEach((rule: { oneOf: any[]; }) => {
      if (rule.oneOf) {
        rule.oneOf.forEach((oneOfRule: { type?: string | undefined; generator?: { filename: string; } | undefined; test?: { test: (arg0: string) => boolean; } | undefined; }) => {
          const assetRule = oneOfRule as { type?: string; generator?: { filename: string; }; test?: { test: (arg0: string) => boolean } };
          
          if (assetRule.type === 'asset') {
            assetRule.generator = {
              filename: 'static/media/[name].[contenthash][ext]',
            };
          }

          if (
            assetRule.test &&
            typeof assetRule.test.test === 'function' &&
            assetRule.test.test('.svg')
          ) {
            assetRule.generator = {
              filename: 'static/media/[name].[contenthash][ext]',
            };
          }
        });
      }
    });

    // 确保公共路径正确设置
    config.output = {
      ...config.output,
      publicPath: './_next/',
    };

    return config;
  },
};

export default nextConfig;

大功告成!现在跑动项目,会发现,我们的 px 变成了 vw,可以自动自适应啦!

相关推荐
Coder-coco1 小时前
在线商城系统|基于springboot vue在线商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·宠物
han_2 小时前
Vue.js 为什么要推出 Vapor Mode?
前端·javascript·vue.js
oden2 小时前
AI重构10000行老代码:2周完成1个月工作量的真实复盘
前端·aigc·ai编程
小满zs2 小时前
Next.js第十二章(RSC/服务端组件/客户端组件)
前端
亿元程序员2 小时前
明明直接用就可以了,非要在Creator里面写???
前端
wadesir3 小时前
Nginx负载均衡代理协议详解(从零开始搭建高可用Web服务)
前端·nginx·负载均衡
秋氘渔3 小时前
Vue 3 组合式写法:侦听器 watch 和 watchEffect 的区别及使用技巧
前端·javascript·vue.js·watch·watcheffect
光头程序员3 小时前
vue学习笔记
vue.js·笔记·学习
想睡八个小时3 小时前
已包含的文件名 “a.vue“ 仅大小写与文件名 “A.vue“ 不同
前端·vscode
阿奇__3 小时前
element二次封装组件套餐 搜索组件 表格组件 弹窗组件
javascript·vue.js·elementui