vite项目页面换肤
本项目仅展示body主题换肤,如有需要请灵活运用~~,效果图如下:
图一:
图二:
1 依赖
本项目是基于vite+ts+vue创建的基础项目,依赖element plus(请按照官方文档自行安装),sass,换肤主要依赖@zougt/vite-plugin-theme-preprocessor:默认支持sass并且在vite.config.js配置后会全局引入这些样式,了解更多@zougt/vite-plugin-theme-preprocessor用法:请点击这里:地址
npm install @zougt/vite-plugin-theme-preprocessor
package.json:如缺少什么依赖请自行安装~~
2 vite.config.js基本配置
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
import Components from "unplugin-vue-components/vite";
import AutoImport from 'unplugin-auto-import/vite';
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import { genScssMultipleScopeVars } from "./src/hooks/common.js";
// https://vitejs.dev/config/
export default defineConfig({
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true
},
scss: {
javascriptEnabled: true
}
}
},
optimizeDeps: {
exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"]
},
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
vue(),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: genScssMultipleScopeVars(),
// 默认取 multipleScopeVars[0].scopeName
// defaultScopeName: "",
// 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
extract: true,
// 独立主题css文件的输出路径,默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
// outputDir: "",
// 会选取defaultScopeName对应的主题css文件在html添加link
themeLinkTagId: "head",
// "head"||"head-prepend" || "body" ||"body-prepend"
themeLinkTagInjectTo: "head",
// 可以自定义css文件名称的函数
// customThemeCssFileName: scopeName => scopeName
// 是否对抽取的css文件内对应scopeName的权重类名移除
removeCssScopeName: false
}
})
],
})
3 代码
src/hooks/common.js
//在实际应用中path和varsContent用一个其实就可以了
type MultipleScopeVarsItem = {
scopeName: string;//需要用到的主题色的模块
path: string;//也可以写一个scss文件定义一些主题样式
varsContent: string;//主题色的内容
};
const themeColors: any = {
default: {
color: "#409EFF",
subMenuActiveText: "#fff",
menuBg: "#1c2233",
menuHover: "#4091f7",
subMenuBg: "#161b29",
subMenuActiveBg: "#343f5d",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#1c2233",
menuTitleHover: "#fff",
menuActiveBefore: "#4091f7"
},
light: {
color: "#409EFF",
subMenuActiveText: "#409eff",
menuBg: "#fff",
menuHover: "#e0ebf6",
subMenuBg: "#fff",
subMenuActiveBg: "#e0ebf6",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#fff",
menuTitleHover: "#000",
menuActiveBefore: "#4091f7"
},
dusk: {
color: "#f5222d",
subMenuActiveText: "#fff",
menuBg: "#2a0608",
menuHover: "#e13c39",
subMenuBg: "#000",
subMenuActiveBg: "#e13c39",
navTextColor: "#red",
menuText: "rgb(254 254 254 / 65.1%)",
sidebarLogo: "#42090c",
menuTitleHover: "#fff",
menuActiveBefore: "#e13c39"
},
volcano: {
color: "#fa541c",
subMenuActiveText: "#fff",
menuBg: "#2b0e05",
menuHover: "#e85f33",
subMenuBg: "#0f0603",
subMenuActiveBg: "#e85f33",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#441708",
menuTitleHover: "#fff",
menuActiveBefore: "#e85f33"
},
yellow: {
color: "#fadb14",
subMenuActiveText: "#d25f00",
menuBg: "#2b2503",
menuHover: "#f6da4d",
subMenuBg: "#0f0603",
subMenuActiveBg: "#f6da4d",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#443b05",
menuTitleHover: "#fff",
menuActiveBefore: "#f6da4d"
},
mingQing: {
color: "#13c2c2",
subMenuActiveText: "#fff",
menuBg: "#032121",
menuHover: "#59bfc1",
subMenuBg: "#000",
subMenuActiveBg: "#59bfc1",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#053434",
menuTitleHover: "#fff",
menuActiveBefore: "#59bfc1"
},
auroraGreen: {
color: "#52c41a",
subMenuActiveText: "#fff",
menuBg: "#0b1e15",
menuHover: "#60ac80",
subMenuBg: "#000",
subMenuActiveBg: "#60ac80",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#112f21",
menuTitleHover: "#fff",
menuActiveBefore: "#60ac80"
},
pink: {
color: "#eb2f96",
subMenuActiveText: "#fff",
menuBg: "#28081a",
menuHover: "#d84493",
subMenuBg: "#000",
subMenuActiveBg: "#d84493",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#3f0d29",
menuTitleHover: "#fff",
menuActiveBefore: "#d84493"
},
saucePurple: {
color: "#722ed1",
subMenuActiveText: "#fff",
menuBg: "#130824",
menuHover: "#693ac9",
subMenuBg: "#000",
subMenuActiveBg: "#693ac9",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#1f0c38",
menuTitleHover: "#fff",
menuActiveBefore: "#693ac9"
}
};
export function genScssMultipleScopeVars(): MultipleScopeVarsItem[] {
const result = [] as MultipleScopeVarsItem[];
Object.keys(themeColors).forEach(key => {
result.push({
scopeName: `layout-theme-${key}`,
varsContent: `$primary-color: ${themeColors[key].color} !default;$vxe-primary-color: $primary-color;$subMenuActiveText: ${themeColors[key].subMenuActiveText} !default;$menuBg: ${themeColors[key].menuBg} !default;$menuHover: ${themeColors[key].menuHover} !default;$subMenuBg: ${themeColors[key].subMenuBg} !default;$subMenuActiveBg: ${themeColors[key].subMenuActiveBg} !default;$navTextColor: ${themeColors[key].navTextColor} !default;$menuText: ${themeColors[key].menuText} !default;$sidebarLogo: ${themeColors[key].sidebarLogo} !default;$menuTitleHover: ${themeColors[key].menuTitleHover} !default;$menuActiveBefore: ${themeColors[key].menuActiveBefore} !default;`
} as MultipleScopeVarsItem);
})
return result;
}
-
src/components/setting.vue<script setup lang="ts"> import { ref } from "vue"; //换肤插件内置方法,可以用来切换主题色 import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"; type themeColorsType = { color: string; themeColor: string; }; const themeColors = ref<Array<themeColorsType>>([ // 道奇蓝(默认) { color: "#1b2a47", themeColor: "default" }, // 亮白色 { color: "#ffffff", themeColor: "light" }, // 猩红色 { color: "#f5222d", themeColor: "dusk" }, // 橙红色 { color: "#fa541c", themeColor: "volcano" }, // 金色 { color: "#fadb14", themeColor: "yellow" }, // 绿宝石 { color: "#13c2c2", themeColor: "mingQing" }, // 酸橙绿 { color: "#52c41a", themeColor: "auroraGreen" }, // 深粉色 { color: "#eb2f96", themeColor: "pink" }, // 深紫罗兰色 { color: "#722ed1", themeColor: "saucePurple" } ]); let dataTheme = ref<boolean>(false); // 设置导航主题色 function setLayoutThemeColor(theme: string) { toggleTheme({ scopeName: `layout-theme-${theme}` }); } // 主题色 激活选择项 const getThemeColor = (val: string) => { return val; }; // 日间、夜间主题切换 function dataThemeChange() { if (dataTheme.value) { setLayoutThemeColor("light"); } else { setLayoutThemeColor("default"); } } </script> <template> <div> <el-divider>主题</el-divider> <el-switch v-model="dataTheme" inline-prompt @change="dataThemeChange"> </el-switch> <el-divider>主题色</el-divider> <ul class="theme-color"> <li v-for="(item, index) in themeColors" :key="index" :style="`background:${item.color};`" @click="setLayoutThemeColor(item.themeColor)"> <el-icon style="margin: 0.1em 0.1em 0 0" :size="17" :color="getThemeColor(item.themeColor)"> <IconifyIconOffline icon="check" /> </el-icon> </li> </ul> </div> </template> <style lang="scss" scoped> .theme-color { width: 100%; height: 40px; margin-top: 20px; display: flex; justify-content: center; li { float: left; width: 20px; height: 20px; margin-top: 8px; margin-right: 8px; font-weight: 700; text-align: center; border-radius: 2px; cursor: pointer; &:nth-child(2) { border: 1px solid #ddd; } } } </style>
-
src/App.vue <template> <div> <setting></setting> </div> </template> <script setup lang="ts"> import setting from "./components/setting.vue" </script> <style lang="scss"> body { background: $sidebarLogo;//这里背景色用了主题色,调用toggleTheme后会自动运用更改过后的主题色 color: #fff; } </style>