在上次在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;}// 手动调用全局的modifyVarsconst 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编写的留神项、转换项以及一些小坑,都在我的项目中有局部正文了。