28 实现多主题切换 - udo-bit/naive_admin_pro GitHub Wiki
完成基础的多主题的功能切换
打开config/layout-theme.ts文件,添加一个新的属性theme,如下:
export interface LayoutTheme {
theme?: string
}
接下来我们在config中创建一个theme的文件用于存放我们的样式。这里的主题色,我们采用的是ant.design提供的主题色,如果大家需要配置更多可以参考antd
import type { GlobalThemeOverrides } from 'naive-ui'
export const colors: Record<string, GlobalThemeOverrides> = {
default: {
common: {
// 主色
primaryColor: '#18a058',
// hover
primaryColorHover: '#36ad6a',
// 按下的颜色
primaryColorPressed: '#0c7a43',
// 反色激活颜色
primaryColorSuppl: '#36ad6a',
},
},
dustRed: {
common: {
primaryColor: '#f5222d',
primaryColorHover: '#ff4d4f',
primaryColorPressed: '#cf1322',
primaryColorSuppl: '#ff4d4f',
},
},
volcano: {
common: {
primaryColor: '#fa541c',
primaryColorHover: '#ff7a45',
primaryColorPressed: '#d4380d',
primaryColorSuppl: '#ff7a45',
},
},
orange: {
common: {
primaryColor: '#fa8c16',
primaryColorHover: '#ffa940',
primaryColorPressed: '#d46b08',
primaryColorSuppl: '#ffa940',
},
},
cyan: {
common: {
primaryColor: '#13c2c2',
primaryColorHover: '#36cfc9',
primaryColorPressed: '#08979c',
primaryColorSuppl: '#36cfc9',
},
},
blue: {
common: {
primaryColor: '#1890ff',
primaryColorHover: '#40a9ff',
primaryColorPressed: '#096dd9',
primaryColorSuppl: '#40a9ff',
},
},
purple: {
common: {
primaryColor: '#722ed1',
primaryColorHover: '#9254de',
primaryColorPressed: '#531dab',
primaryColorSuppl: '#9254de',
},
},
magenta: {
common: {
primaryColor: '#eb2f96',
primaryColorHover: '#f759ab',
primaryColorPressed: '#c41d7f',
primaryColorSuppl: '#f759ab',
},
},
}
export const darkColors: Record<string, GlobalThemeOverrides> = {
default: {
common: {
primaryColor: '#18a058',
primaryColorHover: '#7fe7c4',
primaryColorPressed: '#5acea7',
primaryColorSuppl: 'rgb(42,148,125)',
},
},
dustRed: {
common: {
primaryColor: '#d32029', // 6
primaryColorHover: '#e84749', // 7
primaryColorPressed: '#f37370', // 8
primaryColorSuppl: '#a61d24', // 5
},
},
volcano: {
common: {
primaryColor: '#d84a1b',
primaryColorHover: '#e87040',
primaryColorPressed: '#f3956a',
primaryColorSuppl: '#aa3e19',
},
},
orange: {
common: {
primaryColor: '#d87a16',
primaryColorHover: '#e89a3c',
primaryColorPressed: '#f3b765',
primaryColorSuppl: '#aa6215',
},
},
cyan: {
common: {
primaryColor: '#13a8a8',
primaryColorHover: '#33bcb7',
primaryColorPressed: '#58d1c9',
primaryColorSuppl: '#138585',
},
},
blue: {
common: {
primaryColor: '#177ddc',
primaryColorHover: '#3c9ae8',
primaryColorPressed: '#65b7f3',
primaryColorSuppl: '#1765ad',
},
},
purple: {
common: {
primaryColor: '#642ab5',
primaryColorHover: '#854eca',
primaryColorPressed: '#ab7ae0',
primaryColorSuppl: '#51258f',
},
},
magenta: {
common: {
primaryColor: '#cb2b83',
primaryColorHover: '#e0529c',
primaryColorPressed: '#f37fb7',
primaryColorSuppl: '#a02669',
},
},
}
切换到stores/app.ts中增加覆盖样式的代码如下:
const overridesTheme = computed(() => {
if (isDark.value)
return darkColors[layout.theme]
else
return colors[layout.theme]
})
const updateTheme = (val: string) => {
layout.theme = val
}
return {
overridesTheme,
updateTheme,
}
最后我们在app.vue中增加覆盖主题的功能:
<script setup lang="ts">
const appStore = useAppStore()
const { layoutTheme, overridesTheme } = storeToRefs(appStore)
useAutoDark()
</script>
<template>
<n-config-provider :theme="layoutTheme" :theme-overrides="overridesTheme">
<app-provider>
<router-view />
</app-provider>
</n-config-provider>
</template>
接下来我们在pages/index.vue中进行测试:
<script lang="ts" setup>
import { colors } from '~/config/theme'
const appStore = useAppStore()
const onSwitchTheme = (value: string) => {
appStore.updateTheme(value)
}
</script>
<template>
<div>
<n-space>
<n-button v-for="(color, key) in colors" :key="key" type="primary" @click="onSwitchTheme(key)">
{{ key }}
</n-button>
</n-space>
</div>
</template>
<style scoped>
</style>
当我们切换的时候,会发现我们的按钮的颜色也会跟着变化,那么我们的主题色切换就生效了。
我们在layouts/setting-drawer中增加一个checkbox-colors的文件。如下:
<script lang="ts" setup>
import { CheckOutlined } from '@vicons/antd'
defineProps<{
color: string
checked?: boolean
}>()
</script>
<template>
<div :style="{ background: color }" class="cursor-pointer flex w-20px h-20px items-center justify-center">
<n-icon v-if="checked" size="16">
<CheckOutlined />
</n-icon>
</div>
</template>
在config/theme.ts中定义类型:
export interface ThemeType {
color: string
key: string
}
我们在stores/app.ts中将我们的样式实现:
const themeList = computed<ThemeType[]>(() => {
const list: ThemeType[] = []
const myColors = isDark.value ? darkColors : colors
for (const colorsKey in myColors) {
const value = myColors[colorsKey]
list.push({
color: value.common?.primaryColor as string,
key: colorsKey,
})
}
return list
})
然后再setting-drawer/index.vue中使用:
<script lang="ts" setup>
import CheckboxColor from './checkbox-color.vue'
import type { ThemeType } from '~/config/theme'
const props = withDefaults(defineProps<{
themeList?: ThemeType[]
theme?: string
}>(), {
})
const emit = defineEmits(['update:theme'])
const onChangeTheme = (item: ThemeType) => {
emit('update:theme', item.key)
}
</script>
<template>
<Container v-if="themeList" title="主题色配置">
<n-space>
<CheckboxColor
v-for="item in themeList"
:key="item.key"
:color="item.color"
:checked="item.key === theme"
@click="onChangeTheme(item)"
/>
</n-space>
</Container>
<n-divider />
</template>
然后在base-layout中:
<script lang="ts" setup>
const { layout, visible, layoutList, layoutStyleList, themeList } = storeToRefs(appStore)
</script>
<template>
<SettingDrawer
v-model:layout-style="layout.layoutStyle"
v-model:layout="layout.layout"
v-model:theme="layout.theme"
:theme-list="themeList"
:layout-list="layoutList"
:layout-style-list="layoutStyleList"
/>
</template>
测试效果
我们发现暗黑模式下,在mac中我们上划和下滑的时候,整体的背景色还是不对的,所以我们在app.vue中添加如下导入:
<template>
<n-config-provider :theme="layoutTheme" :theme-overrides="overridesTheme">
+ <n-global-style/>
<app-provider>
<router-view />
</app-provider>
</n-config-provider>
</template>
这样我们的背景就跟着主题色进行变化了。