layout/header.vue
以下为部分代码
<div class="i-item">
<el-dropdown
@command="handleCommandTheme"
popper-class="layout-theme-setting"
placement="bottom">
<i class="my-icon-theme"></i>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="item in themes"
:key="item.label"
:class="{'is-active': theme === item.value}"
:command="item.value">
<i :style="`background: ${item.color}`" :class="{'black-bg': item.black}"/>
<span>{{item.label}}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
import { themes } from '@/utils/theme'
const handleCommandLayout = (val: string) => {
proxy.$store.dispatch('setting/setState', { sideBar: val })
}
layout/index.vue
import { onBeforeMount, provide, watchEffect } from 'vue'
import dom from '@/utils/dom'
onBeforeMount(() => {
watchEffect(() => {
const activeTheme = themes.find(item => item.value === theme.value) // 加载主题
if (activeTheme) {
const el = document.documentElement
el.setAttribute("style", setTheme(activeTheme.key))
dom.replaceClass(document.getElementsByTagName("body")[0], activeTheme.value)
}
})
})
themes.ts
import { colourBlend } from '@/utils/color'
import type { ThemeColors, Theme, TypeObject } from '@/types/global'
const colors: ThemeColors = {
'blue': ['蓝色', '#1377FF'],
'green': ['绿色', '#559C32'],
'dark-blue': ['深蓝', '#364BCA'],
'dark-green': ['青绿', '#009688'],
'red': ['红色', '#F34D37'],
'decor': ['花色', '#264595']
}
export let themes = <Theme[]>[]
Object.entries(colors).forEach(color => {
const _themes = [
{
label: `黑${color[1][0].replace('色', '')}`,
value: `theme-black theme-${color[0]}`,
key: color[0],
color: color[1][1],
black: true
},
{
label: color[1][0],
value: `theme-${color[0]}`,
key: color[0],
color: color[1][1]
}
]
themes = [...themes, ..._themes]
})
/**
* @description 获取主题颜色
*/
export const setTheme = function(key: string): string {
const color = colors[key][1]
const style: TypeObject<string> = {
'--el-color-primary': color,
'--el-color-primary-dark-2': colourBlend('#000000', color, 0.8)
}
for (let i = 1; i < 10; i++) {
style['--el-color-primary-light-' + i] = colourBlend('#ffffff', color, 1 - 0.1 * i)
}
let _style = ''
Object.entries(style).forEach(item => {
_style += `${item[0]}: ${item[1]};`
})
return _style
}
utils/color.ts
import { isArray } from "./validate"
/**
* @description RGB(A)颜色转换为HEX十六进制的颜色值
* @param val - 颜色值
*/
export function rgbToHex(val: string): string {
let r, g, b
const regRgba = /rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3})(,([.\d]+))?\)/
const rsa = val.replace(/\s+/g, '').match(regRgba)
if(isArray(rsa)) {
r = parseInt(rsa[1]).toString(16)
r = r.length === 1 ? '0' + r : r
g = (+rsa[2]).toString(16)
g = g.length === 1 ? '0' + g : g
b = (+rsa[3]).toString(16);
b = b.length === 1 ? '0' + b : b
return '#' + r + g + b
} else {
return val
}
}
/**
* @description HEX十六进制的颜色值转换为RGB(A)颜色
* @param val - 颜色值
*/
export function hexToRgb(val: string): string {
let a, b, c
if ((/^#/g).test(val)) {
a = val.slice(1,3)
b = val.slice(3,5)
c = val.slice(5,7)
return 'rgba(' + parseInt(a, 16) + ', ' + parseInt(b, 16) + ', ' + parseInt(c, 16) + ')'
} else {
return val
}
}
/**
* @description 获取颜色设置透明度 + 底色 之后的颜色值
* @param bgColor - 背景色
* @param color - 当前颜色
* @param opacity - 透明度取值为 0 ~ 1 之间
*/
export function colourBlend(bgColor: string, color: string, opacity: number): string {
opacity = Math.max(Math.min(Number(opacity), 1), 0)
const r1 = parseInt(bgColor.substring(1, 3), 16)
const g1 = parseInt(bgColor.substring(3, 5), 16)
const b1 = parseInt(bgColor.substring(5, 7), 16)
const r2 = parseInt(color.substring(1, 3), 16)
const g2 = parseInt(color.substring(3, 5), 16)
const b2 = parseInt(color.substring(5, 7), 16)
let r = Math.round(r1 * (1 - opacity) + r2 * opacity) as number | string
let g = Math.round(g1 * (1 - opacity) + g2 * opacity) as number | string
let b = Math.round(b1 * (1 - opacity) + b2 * opacity) as number | string
r = ('0' + (r || 0).toString(16)).slice(-2)
g = ('0' + (g || 0).toString(16)).slice(-2)
b = ('0' + (b || 0).toString(16)).slice(-2)
return ('#' + r + g + b).toLocaleUpperCase()
}