没错,我又在vite中尝试了暗黑主题在线切换

在上次在nextjs开发的博客中添加了暗黑主题后(一些网友想要的nextjs博客源码已经上传到github,blog-template-nextjs),这几个月在学习使用vue3及vite开发环境时,想着把暗黑主题也带到我的demo项目中,并构想实现了。

描述:在nextjs中对antd的亮白和暗黑主题切换实践。
在线预览:传送门 在页面的下拉菜单切换主题,目前只准备了黑白,全白和暗黑三种。
代码仓库:vue3-admin

预览图

登录

  1. 暗黑主题

  1. 白色主题

工作台

  1. 暗黑主题

  1. 白色模式

实现

原理:通过antd-theme-generator库,将ant-design-vue中的样式及项目中使用到的样式(less编写)抽出放到color.less中,再通过getLessVars方法挨个将多个主题变量配置打包成json文件并在项目中引用,最后在生产环境中通过调用less.modifyVars方法修改全局样式(less会根据提供的变量值,删除当前的style标签,重新生成新的样式标签)

核心代码

由于是在vite环境中antd-theme-generator作者提供的antd-theme-webpack-plugin没法使用,所以这里写了一个简单版的vite插件替换:vite-plugin-antd-theme。主要是封装了一下生成json的行为和自动调用generateTheme方法。

安装vite-plugin-antd-theme

yarn add vite-plugin-antd-theme -D
 

vite-plugin-antd-theme中已主动依赖了antd-theme-generator,所以主项目不需要再次安装,也不需要从中导入方法,并且vite-plugin-antd-theme导出了antd-theme-generator所需的入参类型。


vite.config.ts

import path from 'path';
import { UserConfigExport, ConfigEnv } from 'vite';
import viteAntdTheme, { ThemeEntry, AntdThemeOptions } from 'vite-plugin-antd-theme';
const themesEntry: Array<ThemeEntry> = [
// 暗黑主题
{
entryPath: './node_modules/ant-design-vue/lib/style/themes/dark.less',
outputName: 'dark',
outputPath: './src/config'
},
// 默认主题
{
entryPath: './src/styles/vars.less',
outputName: 'light',
outputPath: './src/config'
},
// 紧凑主题
{
entryPath: './node_modules/ant-design-vue/lib/style/themes/compact.less',
outputName: 'compact',
outputPath: './src/config'
}
];
const options: AntdThemeOptions = {
themesEntry,
// 是否提取全部变量,默认false,优先级低于设置themeVariables
allVariables: true,
// 以下是antd-theme-generator配置项
antDir: path.join(__dirname, './node_modules/ant-design-vue'),
stylesDir: path.join(__dirname, './src'), // all files with .less extension will be processed
varFile: path.join(__dirname, './src/styles/vars.less'), // default path is Ant Design default.less file
themeVariables: [],
outputFilePath: path.join(__dirname, './public/static/color.less'), // if provided, file will be created with generated less/styles
customColorRegexArray: [/^fade\(.*\)$/] // An array of regex codes to match your custom color variable values so that code can identify that it's a valid color. Make sure your regex does not adds false positives.
};
export default ({ command }: ConfigEnv): UserConfigExport => {
return {
plugins: [
viteAntdTheme(options)
]
};
};

可以看出默认的配置项仍然很多,计划在1.0.2之后的版本会将默认项封装。


styles/vars.less

// This file will contain all varibales, our custom varibales and
//those from Ant Design which we want to override.
@import '../../node_modules/ant-design-vue/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;
}
 

这里可以自定义主题色,变量名含义主要参考ant-design-vue。


index.html

<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<link rel="stylesheet/less" type="text/css" href="/static/color.less" />
<script src="/static/libs/less.min.js"></script>
</body>

这里需要准备一份2.7.3版本的浏览器端运行的less,用于在线修改主题样式,color.less会在运行项目时自动生成(bug:目前发现首次运行build时,会提示没有color.less的问题,暂未修复,目前最好在build前都跑一遍dev)。


main.ts

这里全局引入antd的less样式即可。

import 'ant-design-vue/dist/antd.less';

store/modules/setting.ts

import Final from '@/config/keys';
import darkVars from '@/config/dark.json';
import lightVars from '@/config/light.json';
export type Themes = 'dark' | 'light' | 'mix';
export interface SettingStateType {
// 主题
theme: Themes;
}
// 手动调用全局的modifyVars
const lessHandler = (themeName: Themes) => {
switch (themeName) {
case 'dark': {
(window as any).less.modifyVars(darkVars);
break;
}
case 'light': {
(window as any).less.modifyVars(lightVars);
break;
}
case 'mix': {
(window as any).less.modifyVars(lightVars);
}
}
};
// 读取缓存的主题
const cacheTheme = localStorage.getItem(Final.THEME);
const state: SettingStateType = {
theme:
(cacheTheme === 'dark' && 'dark') ||
(cacheTheme === 'light' && 'light') ||
(cacheTheme === 'mix' && 'mix') ||
'dark'
};
// 首次自动修改主题
lessHandler(state.theme);
const mutations = {
// 切换主题
themeChanged(state: SettingStateType, payload: { theme: Themes }): void {
state.theme = payload.theme;
localStorage.setItem(Final.THEME, payload.theme);
lessHandler(payload.theme);
}
};
const actions = {};
export default {
namespaced: true,
state,
mutations,
actions
};

vue3-admin的实现是提交mutation来自动触发主题修改逻辑。

至此就大致实现了功能,只需要添加触发器即可。

写在文末

vue3-admin是一个使用vue3系列,vite开发环境及纯tsx语法开发的后台管理项目,虽然vue主推的是模板语法,但是也希望这种方式能够让你学习到一些东西。作者主要觉得可以拉近react与vue之间的距离,而且tsx编写的过程,vscode能更友好的提示。关于tsx编写的注意项、转换项以及一些小坑,都在项目中有部分注释了。

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/14643.html

发表评论

登录后才能评论