不能不说,写这个的时候,真的好饿!
形容:在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中。