Vue3主题变更

207 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

通过全局样式配置,实现系统主题颜色的切换:

代码:

文件constant.scss 配置颜色值和变量之间的关系

:root{
     // 主题色
     --ry-primary-color: #31a8fa;
     // layout部分
     --ry-header-height: 60px;
     --ry-logo-color: #5d5d5d;
     --ry-logo-background-color: #fff;
 
     // element主题色修改
     --el-color-primary: var(--ry-primary-color);
}

文件theme.ts 定义主题类型接口,封装主题所需主题数据结构


export interface Color {
    primary: {
        color: String
    }
    logo: {
        color: string
        backgroundColor: string
    }
}

export interface Style {
    light: Color
    dark: Color
}

export const style: Style = {
    "light": {
        primary: {
            color: '#31a8fa'
        },
        logo: {
            color: '#5d5d5d',
            backgroundColor: '#fff'
        }
    },
    "dark": {
        primary: {
            color: '#282724'
        },
        logo: {
            color: '#fff',
            backgroundColor: '#fff'
        }
    }
}


文件header.vue使用:

<template>
    <el-header class="c-header">
        <h1>{{ systemTitle }}</h1>
        <div class="header-right">
            <div class="util-content">
                <el-icon class="more-style-icon" title="更多主题" @click="showMoreStyle">
                    <Grid />
                </el-icon>
            </div>
            您好:{{ personName }}
            <span class="log-out" @click="logout">退出</span>
        </div>
        <el-drawer v-model="show" title="主题颜色">
            <div class="theme-list-container">
                <div v-for="item, i in themesStyle" class="theme-item" @click="changeTheme(item)"
                    :style="{ backgroundColor: item.primary.color }"></div>
            </div>
        </el-drawer>
    </el-header>
</template>
<script lang="ts">
import { defineComponent, inject, ref, reactive } from 'vue'
import { userInfoStore } from '../../stores/userInfo'
import { useRouter } from 'vue-router'
import { Grid } from '@element-plus/icons-vue'
import { style, type Color, type Style } from '@/utils/theme'
import { collapseItemProps } from 'element-plus'
export default defineComponent({
    setup() {
        const show = ref(false)
        const systemTitle = inject("systemTitle")
        const cookieTool: any = inject("CookieTool")
        const userInfo = userInfoStore()
        const personName = userInfo.personName
        const router = useRouter()
        const logout = function () {
            //清空store
            userInfo.$reset()
            cookieTool.delete("person_id")
            cookieTool.delete("person_name")
            router.push("/toLogin")
        }
        const showMoreStyle = function () {
            document.documentElement.style.setProperty('--theme-color', 'red')
            show.value = true
        }

        //主题选择区
        const themeStyle = style;
        const themes = Object.keys(themeStyle)
        var themesStyle: any = reactive([])
        themes.forEach(item => {
            themesStyle.push(themeStyle[item as keyof Style])
        })
      
        //点击改变主题
        const changeTheme = (theme: Color) => {
            console.log("theme:", theme)
            const root = document.documentElement
            for (let i in theme) {
                const item: any = theme[i as keyof Color]
                for (let j in item) {
                    const cssVarName =
                        '--ry-' + i + '-' + j.replace(/([A-Z])/g, '-$1').toLowerCase()
                    root.style.setProperty(cssVarName, item[j])
                }
            }
        }

        return {
            systemTitle,
            personName,
            logout,
            show,
            showMoreStyle,
            themesStyle,
            changeTheme
        }
    },
    components: {
        Grid
    }
})
</script>
<style scoped lang="scss">
.c-header {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: var(--ry-primary-color);
    color: var(--ry-logo-background-color);

    .header-right {
        position: relative;
        display: flex;

        .util-content {
            display: flex;
            align-items: center;
            margin-right: 10px;
            padding: 0 5px;

            .more-style-icon {
                cursor: pointer;
            }
        }

        .log-out {
            margin-left: 20px;
            text-decoration: underline;
            cursor: pointer;
            margin-right: 10px;
        }

    }

    .theme-list-container {
        width: 100%;
        height: 100%;
        display: flex;
        flex-wrap: nowrap;

        .theme-item {
            width: 50px;
            height: 50px;
            margin-right: 20px;
            cursor: pointer;
        }
    }
}
</style>

image.png

此例子只有两种主题,如果还需要更多主题,可以在theme.ts中进行配置