关于react.js:在nextjs中捣腾一下暗黑主题

6次阅读

共计 3874 个字符,预计需要花费 10 分钟才能阅读完成。

不能不说,写这个的时候,真的好饿!

形容 :在 nextjs 中对 antd 的亮白和暗黑主题切换实际。
在线预览 :https://zhoubangfu.com/demo/theme 18:00-7:00 是暗黑主题,能够通过 Redux DevTools 提交 action, {type: 'change_theme',value: 'dark/light'} 来切换,或者在预览页面的下拉菜单切换也能够。
代码仓库:https://github.com/zhoubangfu/nextjs-start

预览图

次要用到一个 webpack 插件antd-theme-webpack-plugin。上面会一步一步的造~

这个插件是基于应用 webpack 环境的,临时没有去看有没有大佬有开发反对 vite 的插件。在反对服务端渲染的我的项目中有了实际,那么在单页利用客户端渲染的我的项目中,就大同小异了。

搭建我的项目

其中增加 redux、舍弃 nextjs 本身的 css 应用 withCss 插件、增加 less\sass 以及反对模块款式的内容就不谈了,内容很简略,能够间接看代码。

增加主题依赖

yarn add -D antd-theme-webpack-plugin

配置项

1. 增加自定义的主题

向 styles 文件夹中增加 vars.less,内容能够像上面:

// This file will contain all varibales, our custom varibales and
//those from Ant Design which we want to override.
@import '~antd/lib/style/themes/default.less';
@primary-color: @green-6;
@select-item-selected-option-color: @primary-color;
@processing-color: @primary-color;
@select-item-selected-bg: @background-color-base;
@secondary-color: @primary-color;
@skeleton-color: @primary-color;
@btn-primary-bg: @primary-color;

:root {--PC: @primary-color;}

此内容来自 nextjs 的 demo

2. 增加 next 配置

next.config.js

const AntDesignThemePlugin = require('antd-theme-webpack-plugin');
// antd-theme-generator 插件在下面的依赖我的项目中有,所以不须要装置
const {getLessVars} = require('antd-theme-generator');

// 这一步是读取咱们预设的次要的主题变量(是不反对热更新的)const themeVariables = getLessVars(path.join(__dirname, './src/styles/vars.less'));

// 读取暗黑主题
const darkVars = {...getLessVars('./node_modules/antd/lib/style/themes/dark.less'),
  '@picker-basic-cell-active-with-range-color': 'darken(@primary-color, 20%)'
};

// 亮白主题
const lightVars = {...getLessVars('./node_modules/antd/lib/style/themes/compact.less')
};

// 这一步即便启动或构建我的项目时生成对应的主题文件,用于我的项目中 import
// 最好的 gitignore 该生成的文件,每次主动生成
fs.writeFileSync('./src/config/dark.json', JSON.stringify(darkVars));
fs.writeFileSync('./src/config/light.json', JSON.stringify(lightVars));
fs.writeFileSync('./src/config/theme.json', JSON.stringify(themeVariables));

// 这里就是 theme 插件的配置项了
const themeOptions = {stylesDir: path.join(__dirname, './src'),
  antDir: path.join(__dirname, './node_modules/antd'),
  varFile: path.join(__dirname, './src/styles/vars.less'),
  themeVariables: Array.from(
    new Set([...Object.keys(darkVars),
      ...Object.keys(lightVars),
      ...Object.keys(themeVariables)
    ])
  ),
  indexFileName: false,
  // 这里须要将生成的 less 文件放到一个生产环境可能间接通过 link 获取的中央,所以这里放到 public 下
  outputFilePath: path.join(__dirname, './public/color.less'),
  generateOnce: false
};

module.exports = withPlugins([withLess], {
  lessLoaderOptions: {
    javascriptEnabled: true,
    importLoaders: 1
  },
  webpack: (config, options) => {
    // 增加主题切换 webpack 插件
    config.plugins.push(new AntDesignThemePlugin(themeOptions));
  }
}

这部分即便最次要的配置内容,前面将开始应用该配置生成的内容了

3. 增加切换主题内容

因为 nextjs 中是没有 html 文件的,所以咱们不能像 Nextjs 的 demo 一样间接增加标签引入内容,然而能够略微变通一下。

这里抉择在 pages 下的_app.tsx 动静增加该内容

留神:如果像 https://github.com/zhoubangfu/nextjs-start 中的源码一样,应用了 redux 或 mobx 之类的跨组件状态治理的话,在 Provider 所在主题可能不能很好的提交 action,能够抉择在更深层的公共组件中实现,比方 Layout 中。

_app.tsx

import {useEffect} from 'react';

// 开发阶段导入 json,共线上环境间接应用
import darkVars from '../config/dark.json';
import lightVars from '../config/light.json';
// import themeVars from '../config/theme.json';

const Layout = ({Component, pageProps}) => {useEffect(() => {window['less'] = {
      async: true,
      env: 'production'
    };

    const script = document.createElement('script');

    // 等到 less 加载实现后执行,省得报错
    script.addEventListener('load', () => {window['less']
        .modifyVars(config.name === 'light' ? lightVars : darkVars)
        .catch((error) => {console.error(error);
        });
    });
    
    // 重点,高于 2.7.3 版本的 less 在浏览器端运行会抛错,能够本人踩踩看
    script.src = 'https://cdn.bootcdn.net/ajax/libs/less.js/2.7.3/less.min.js';
    document.body.appendChild(script);

    const css = document.createElement('link');
    css.href = '/color.less';
    css.rel = 'stylesheet/less';
    css.type = 'text/css';
    document.body.appendChild(css);
  }, []);

  return (<Component {...pageProps} />);
};

export default Layout;

从代码中能够看进去,实际上切换主题只是运行了window.less.modifyVars,所以咱们只须要将切换主题的下拉框抉择工夫与其绑定即可

4. 在 sass 中适配

less 的变量不要想着间接拿到 sass 中间接应用(兴许有方法),我在博客中采纳的办法是最简略的皮肤切换形式:批改内部 className,新增 dark 对应的款式。

如此,在调用 window.less.modifyVars 后,能够提交 redux action 批改对应的 state,而后切换内部的 class,这算得上是工作量和难度都较低的办法了。

写在开端

其中的解决方案来自网络,作者只是抽时间将所学拼在了一起。次要的内容还是来自 nextjs 的 github demo 中。

正文完
 0