vite + Ant-Design-Vue 实现动态主题切换

5,458 阅读2分钟

背景

最近在搭建一个后台管理系统时遇到一个在线切换主题的需求,由于项目使用的是vite + Ant-Design-Vue搭建的,在网上找了一圈发现基于webpack的,就很苦恼。好在看到了这位老哥的帖子,他写的这个vite插件很好的解决了这个需求。

原贴传送门: 基于less和sass的在webpack或vite中的预设多主题的编译方案

使用

这插件使用其实很简单,楼下再细说。先看看效果图:

主题切换.gif

安装

  • npm npm install @zougt/vite-plugin-theme-preprocessor -D
  • yarn yarn add @zougt/vite-plugin-theme-preprocessor -D

配置

  • vite.config.ts
import { defineConfig } from "vite";
import path from "path";
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";

export default defineConfig({
  plugins: [
    // 引入插件
    themePreprocessorPlugin({
      // 使用Less
      less: {
        // 此处配置自己的主题文件
        multipleScopeVars: [
          {
            scopeName: "theme-default",
            path: path.resolve("src/assets/theme/default.less"),
          },
          {
            scopeName: "theme-dark",
            path: path.resolve("src/assets/theme/dark.less"),
          },
        ],
        defaultScopeName: "theme-default", // 默认取 multipleScopeVars[0].scopeName
        extract: false,// 在生产模式是否抽取独立的主题css文件
      },
    }),
  ]
});

定制主题

自定义主题文件里可通过覆盖Ant-Design-Vue官方主题变量、使用自定义变量、自定义样式等方式实现主题的定制。以下是两种主题的文件示例:

  • default.less
// 引入官方主题
@import "node_modules/ant-design-vue/lib/style/themes/default";

// 修改组件库主题
@primary-color: red;

// 自定义变量
@custom-color: #000000;

// 自定义全局样式
.login_bg {
  background: url("@/assets/images/login/bg.jpg") no-repeat 100% 100%;
  background-size: cover;
}
  • dark.less
// 引入官方主题
@import "node_modules/ant-design-vue/lib/style/themes/dark";

// 修改组件库主题
@primary-color: blue;

// 自定义变量
@custom-color: #ffffff;

// 自定义全局样式
.login_bg {
  background: url("@/assets/images/login/bg_daek.jpg") no-repeat 100% 100%;
  background-size: cover;
}

切换主题

根据在配置插件时extract选项的值,切换主题时的操作有些许不同。

  • extract: true
const toggleTheme = (scopeName = "theme-default") => {
  let styleLink = document.getElementById("theme-link-tag");
  if (styleLink) {
    // 假如存在id为theme-link-tag 的link标签,直接修改其href
    styleLink.href = `/${scopeName}.css`;
    // 注:如果是removeCssScopeName:true移除了主题文件的权重类名,就可以不用修改className 操作
    document.documentElement.className = scopeName;
  } else {
    // 不存在的话,则新建一个
    styleLink = document.createElement("link");
    styleLink.type = "text/css";
    styleLink.rel = "stylesheet";
    styleLink.id = "theme-link-tag";
    styleLink.href = `/${scopeName}.css`;
    // 注:如果是removeCssScopeName:true移除了主题文件的权重类名,就可以不用修改className 操作
    document.documentElement.className = scopeName;
    document.head.append(styleLink);
  }
};
  • extract: false
const toggleTheme = (scopeName = "theme-default") => {
    document.documentElement.className = scopeName;
};

在实际项目操作中,强烈建议将当前主题通过localstorege或者cookie之类的方式缓存至浏览器中,并在用户在关闭浏览器或刷新后重新取出并初始化主题,这样就不会丢失主题影响体验。

也可将本地缓存搭配Vuex使用,将切换主题操作放入actions中,统一管理主题状态。

后记

最后再次感谢zgt_不梦 大佬的插件~