vue3 + element-plus 实现一键换肤

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()
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值