更换系统主题颜色是常见的前端需求,例如:白天、黑夜系统颜色的变换;电子书中的护眼模式等。
下面是一种解决方案;
在中App.vue
import { watchEffect } from "vue";
import { useSystemSkin } from '@/store/theme';
const themeStore = useSystemSkin();
// route.query.*** 有变动的时候触发一次
watchEffect(() => {
if (!route.query.***) return
// 初始化加载主题
themeStore.initQueryMapColor(route.query.***);
})
/store/theme
状态管理
import { ref } from "vue";
import { defineStore } from 'pinia';
import urls from "@/fetch/url.js";
import { injectThemeVariables } from '@/utils/themeLoader';
// 系统皮肤
export const useSystemSkin = defineStore("systemSkin", () => {
const skinColor = ref("themePurple") // 默认主题
const initQueryMapColor = (e) => {
// 接口查询 主题
urls.queryMapColor({
theme: e
}).then(res => {
if (res.code == 200) {
skinColor.value = res.data || 'themePurple'
}
}).finally(old => {
injectThemeVariables(skinColor.value);
});
}
return { skinColor, initQueryMapColor };
});
/utils/themeLoader
// 默认主题配置
const themeSkin = {
themePurple: {
'--main-color-11': '#5566f3',
'--main-color-10': '#5566f3',
'--main-color-6': 'rgba(85, 102, 243, 0.6)',
'--main-color-4': 'rgba(85, 102, 243, 0.4)',
'--main-color-3': 'rgba(85, 102, 243, 0.3)',
'--main-color-2': 'rgba(85, 102, 243, 0.2)',
'--main-color-1': 'rgba(85, 102, 243, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(85, 102, 243, 0.4) 0%, rgba(85, 102, 243, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(85, 102, 243, 0.3) 0%, rgba(85, 102, 243, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(85, 102, 243, 0.1) 0%, rgba(85, 102, 243, 0) 100%)',
},
themeBlue: {
'--main-color-11': '#006DFB',
'--main-color-10': '#006DFB',
'--main-color-6': 'rgba(1, 112, 240, 0.6)',
'--main-color-4': 'rgba(1, 112, 240, 0.4)',
'--main-color-3': 'rgba(1, 112, 240, 0.3)',
'--main-color-2': 'rgba(1, 112, 240, 0.2)',
'--main-color-1': 'rgba(1, 112, 240, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(1, 112, 240, 0.4) 0%, rgba(1, 112, 240, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(1, 112, 240, 0.3) 0%, rgba(1, 112, 240, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(1, 112, 240, 0.1) 0%, rgba(1, 112, 240, 0) 100%)',
},
themeCyan: {
'--main-color-11': '#00CECE',
'--main-color-10': '#00CECE',
'--main-color-6': 'rgba(0, 206, 206, 0.6)',
'--main-color-4': 'rgba(0, 206, 206, 0.4)',
'--main-color-3': 'rgba(0, 206, 206, 0.3)',
'--main-color-2': 'rgba(0, 206, 206, 0.2)',
'--main-color-1': 'rgba(0, 206, 206, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(0, 206, 206, 0.4) 0%, rgba(0, 206, 206, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(0, 206, 206, 0.3) 0%, rgba(0, 206, 206, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(0, 206, 206, 0.1) 0%, rgba(0, 206, 206, 0) 100%)',
},
themeGreen: {
'--main-color-11': '#008E21',
'--main-color-10': '#008E21',
'--main-color-6': 'rgba(0, 142, 33, 0.6)',
'--main-color-4': 'rgba(0, 142, 33, 0.4)',
'--main-color-3': 'rgba(0, 142, 33, 0.3)',
'--main-color-2': 'rgba(0, 142, 33, 0.2)',
'--main-color-1': 'rgba(0, 142, 33, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(0, 142, 33, 0.4) 0%, rgba(0, 142, 33, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(0, 142, 33, 0.3) 0%, rgba(0, 142, 33, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(0, 142, 33, 0.1) 0%, rgba(0, 142, 33, 0) 100%)',
},
themeYellow: {
'--main-color-11': '#f0c800',
'--main-color-10': '#f0c800',
'--main-color-6': 'rgba(240, 200, 0, 0.6)',
'--main-color-4': 'rgba(240, 200, 0, 0.4)',
'--main-color-3': 'rgba(240, 200, 0, 0.3)',
'--main-color-2': 'rgba(240, 200, 0, 0.2)',
'--main-color-1': 'rgba(240, 200, 0, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(240, 200, 0, 0.4) 0%, rgba(240, 200, 0, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(240, 200, 0, 0.3) 0%, rgba(240, 200, 0, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(240, 200, 0, 0.1) 0%, rgba(240, 200, 0, 0) 100%)',
},
themeOrange: {
'--main-color-11': '#E67F00',
'--main-color-10': '#E67F00',
'--main-color-6': 'rgba(230, 127, 0, 0.6)',
'--main-color-4': 'rgba(230, 127, 0, 0.4)',
'--main-color-3': 'rgba(230, 127, 0, 0.3)',
'--main-color-2': 'rgba(230, 127, 0, 0.2)',
'--main-color-1': 'rgba(230, 127, 0, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(230, 127, 0, 0.4) 0%, rgba(230, 127, 0, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(230, 127, 0, 0.3) 0%, rgba(230, 127, 0, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(230, 127, 0, 0.1) 0%, rgba(230, 127, 0, 0) 100%)',
},
themeRed: {
'--main-color-11': '#E03000',
'--main-color-10': '#E03000',
'--main-color-6': 'rgba(224, 48, 0, 0.6)',
'--main-color-4': 'rgba(224, 48, 0, 0.4)',
'--main-color-3': 'rgba(224, 48, 0, 0.3)',
'--main-color-2': 'rgba(224, 48, 0, 0.2)',
'--main-color-1': 'rgba(224, 48, 0, 0.1)',
'--main-gradient-4': 'linear-gradient(180deg, rgba(224, 48, 0, 0.4) 0%, rgba(224, 48, 0, 0) 100%)',
'--main-gradient-3': 'linear-gradient(270deg, rgba(224, 48, 0, 0.3) 0%, rgba(224, 48, 0, 0) 100%)',
'--main-gradient-1': 'linear-gradient(180deg, rgba(224, 48, 0, 0.1) 0%, rgba(224, 48, 0, 0) 100%)',
}
};
export const injectThemeVariables = (variables) => {
let theme = themeSkin[variables]
// 移除旧主题样式
// const oldStyle = document.getElementById('dynamic-theme');
// if (oldStyle) oldStyle.remove();
// 创建新样式节点
const style = document.createElement('style');
style.id = 'dynamic-theme';
style.type = 'text/css';
// 生成CSS变量声明
let cssContent = ':root {';
Object.entries(theme).forEach(([key, value]) => {
cssContent += `${key}: ${value};`;
});
cssContent += '}';
style.textContent = cssContent;
document.head.appendChild(style);
};
实际使用
// 例如 .css
color: var(--main-color-10);
background: var(--main-color-2);
.js
// 在Vue组件中,通过getComputedStyle获取CSS变量的实际值:
const el = document.documentElement; // 或具体元素
const mainColor = getComputedStyle(el).getPropertyValue('--main-color-2').trim();
// 或者
// utils/color.js
export const getCssVariableColor = (variableName) => {
return getComputedStyle(document.documentElement)
.getPropertyValue(variableName).trim();
};
// 在组件中使用
import { getCssVariableColor } from '@/utils/color';
const mainColor = getCssVariableColor('--main-color-2');