web项目或其他项目中难免有切换主题的需求,现在写一个较统一的方法
本篇文章记录的是:定义好需要的样式,切换主题时将其设置为 html 的自定义属性,从而达到样式替换的效果
还有一种方案:将不同的样式文件使用<link>标签关联到根文件的 html 文件头部,切换主题时,设置 link 标签 的 href 属性即可
import {watchEffect, ref} from 'vue'
const LOCAL_KEY = "__theme__"
export default function useTheme() {
// 1. 主题列表(支持的主题及对应颜色)
const themeColors = ref([
{color: '#409eff', themeKey: 'classicBlue', themeName: "经典蓝色"},
{color: '#312e6c', themeKey: 'deepPurple', themeName: "深邃紫"},
]);
const DEFAULT_THEME = themeColors.value[0].themeKey; // 默认主题
const storedTheme = localStorage.getItem(LOCAL_KEY);
const theme = ref(
storedTheme ? JSON.parse(storedTheme).themeKey : DEFAULT_THEME
);
// 3. 监听主题变化:同步到DOM和本地存储
watchEffect(() => {
// 设置html的data-theme属性(用于CSS选择器)
document.documentElement.dataset.theme = theme.value;
// 保存到本地存储(持久化)
let find = themeColors.value.find(it => it.themeKey === theme.value);
localStorage.setItem(LOCAL_KEY, JSON.stringify(find));
});
// 主题切换方法(对外暴露)
const setTheme = (newTheme) => {
// 验证新主题是否在支持的列表中(可选,增强健壮性)
const isValid = themeColors.value.some(item => item.themeKey === newTheme) || newTheme === 'light';
if (isValid) {
theme.value = newTheme;
}
};
// 获取当前主题
function getTheme() {
return theme.value;
}
// 获取主题对应的背景色
function getThemeColorStyle(color) {
return {background: color};
}
// 获取存储键
function getLocalKey() {
return LOCAL_KEY;
}
// 获取默认的主题
function getDefaultTheme() {
return DEFAULT_THEME;
}
return {
theme,
getTheme,
setTheme,
getLocalKey,
getThemeColorStyle,
themeColors,
getDefaultTheme
}
}
<el-dropdown-item command="theme" class="skin-dropitem">
{{ $t('homePage.switchTheme') }}
<!-- 主题列表-->
<div class="skin-btns">
<div class="themeColors_box">
<div v-for="(item, index) in themeColors" :key="index"
@click="setTheme(item.themeKey)">{{item.themeName}}
</div>
</div>
</div>
</el-dropdown-item>
// js
import useTheme from "@/utils/hooks/useTheme";
const { themeColors, setTheme} = useTheme()
如果自定义的主题颜色与组件库样式终突,导致自定义的样式不生效,可在浏览器dom树中查引用的变量,直接修改变量样式即可,类似于下方的【--el-color-primary-light-9: #93c6fa; // 鼠标滑过.el-button背景色】
// 经典蓝色
html[data-theme="classicBlue"] {
--currentMessage-bg-color: #409eff; // 消息页面分类按钮背景
--sidebar-bg-color: #409eff; // 主页面导肮栏背景
--sidebar-is-active-bg-color: #245a8d; // 主页面导肮栏激活的背景
--sidebar-hover-bg-color: #3278bf; // 主页面导肮栏鼠标滑过的背景
--el-button--primary: #409eff; // element-plus 样式
--el-color-primary-light-9: #93c6fa; // 鼠标滑过.el-button背景色
}
// 深邃紫
html[data-theme="deepPurple"] {
--currentMessage-bg-color: #312e6c;
--sidebar-bg-color: #312e6c;
--sidebar-hover-bg-color: #4a449d;
--sidebar-is-active-bg-color: #181837;
--el-button--primary: #312e6c;
--el-color-primary-light-9: #938fff;
}
import "../../styles/theme.scss"; // 主题颜色