useTheme Composable
useTheme 是 N-UI 提供的主题管理 composable,封装了主题切换、自定义主题、后端加载、导出和持久化能力。
基本用法
ts
import { useTheme } from '@n-ui/hooks'
const {
currentThemeName,
currentTheme,
isDark,
isLoading,
error,
setTheme,
applyCustomTheme,
toggleDark,
loadTheme,
exportTheme,
reset,
} = useTheme({
storageKey: 'n-ui:theme',
defaultTheme: 'default',
})选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
storageKey | string | 'n-ui:theme-name' | localStorage 键名 |
defaultTheme | 'default' | 'light' | 'dark' | 'default' | 默认预设主题 |
返回值
| 属性/方法 | 类型 | 说明 |
|---|---|---|
currentThemeName | Ref<PresetName | 'custom'> | 当前主题名 |
currentTheme | ComputedRef<ThemeConfig> | 当前完整主题配置 |
isDark | ComputedRef<boolean> | 是否为暗色模式 |
isLoading | Ref<boolean> | 远程加载中状态 |
error | Ref<string | null> | 错误信息 |
setTheme(name) | (name: PresetName) => void | 切换预设主题 |
applyCustomTheme(config) | (config: ThemeConfig) => void | 应用自定义主题 |
toggleDark() | () => void | 切换亮/暗模式 |
loadTheme(url) | (url: string) => Promise<void> | 从远程加载主题 JSON |
exportTheme() | () => ThemeConfig | 导出当前主题配置 |
reset() | () => void | 重置为默认主题 |
示例
预设切换
vue
<script setup lang="ts">
import { useTheme } from '@n-ui/hooks'
const { setTheme, currentThemeName } = useTheme()
</script>
<template>
<button
v-for="name in ['default', 'light', 'dark']"
:key="name"
:class="{ active: currentThemeName === name }"
@click="setTheme(name)"
>
{{ name }}
</button>
</template>自定义主题
ts
import { useTheme } from '@n-ui/hooks'
import type { ThemeConfig } from '@n-ui/themes'
const { applyCustomTheme } = useTheme()
const brandTheme: ThemeConfig = {
name: 'brand',
mode: 'light',
colors: {
primary: '#7c3aed',
success: '#22c55e',
warning: '#f59e0b',
danger: '#ef4444',
info: '#6b7280',
text: '#1f2937',
textRegular: '#4b5563',
textSecondary: '#6b7280',
textPlaceholder: '#9ca3af',
border: '#e5e7eb',
borderLight: '#f3f4f6',
borderLighter: '#f9fafb',
borderExtraLight: '#ffffff',
fill: '#f9fafb',
fillLight: '#f3f4f6',
fillLighter: '#e5e7eb',
fillExtraLight: '#ffffff',
fillBlank: '#ffffff',
bg: '#ffffff',
bgPage: '#f8fafc',
bgOverlay: '#ffffff',
},
typography: {
fontSizeExtraLarge: '20px',
fontSizeLarge: '18px',
fontSizeMedium: '16px',
fontSizeBase: '14px',
fontSizeSmall: '13px',
fontSizeExtraSmall: '12px',
fontFamily: "'Inter', 'Helvetica Neue', Helvetica, 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif",
},
borderRadius: {
base: '8px',
small: '4px',
round: '24px',
circle: '100%',
},
spacing: {
xs: '4px',
sm: '8px',
base: '16px',
lg: '24px',
xl: '32px',
},
shadows: {
base: '0px 10px 24px 2px rgba(0, 0, 0, 0.04), 0px 6px 16px rgba(0, 0, 0, 0.06)',
light: '0px 0px 10px rgba(0, 0, 0, 0.08)',
lighter: '0px 0px 4px 0px rgba(0, 0, 0, 0.04)',
dark: '0px 14px 40px 12px rgba(0, 0, 0, 0.02), 0px 10px 24px rgba(0, 0, 0, 0.04), 0px 6px 12px -6px rgba(0, 0, 0, 0.08)',
},
transitionDuration: '0.3s',
transitionDurationFast: '0.2s',
}
applyCustomTheme(brandTheme)远程加载
vue
<script setup lang="ts">
import { useTheme } from '@n-ui/hooks'
const { loadTheme, isLoading, error } = useTheme()
async function loadRemoteTheme() {
await loadTheme('/api/theme/current')
}
</script>
<template>
<button :loading="isLoading" @click="loadRemoteTheme">加载远程主题</button>
<p v-if="error" class="error">{{ error }}</p>
</template>导出主题
ts
import { useTheme } from '@n-ui/hooks'
const { exportTheme } = useTheme()
function downloadTheme() {
const theme = exportTheme()
const blob = new Blob([JSON.stringify(theme, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${theme.name}.json`
a.click()
URL.revokeObjectURL(url)
}