VUE-动态更换系统主题颜色

更换系统主题颜色是常见的前端需求,例如:白天、黑夜系统颜色的变换;电子书中的护眼模式等。
下面是一种解决方案;

在中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');
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容