Skip to content

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',
})

选项

选项类型默认值说明
storageKeystring'n-ui:theme-name'localStorage 键名
defaultTheme'default' | 'light' | 'dark''default'默认预设主题

返回值

属性/方法类型说明
currentThemeNameRef<PresetName | 'custom'>当前主题名
currentThemeComputedRef<ThemeConfig>当前完整主题配置
isDarkComputedRef<boolean>是否为暗色模式
isLoadingRef<boolean>远程加载中状态
errorRef<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)
}