主题
NetNexus UI 的主题由运行时主题管理器、<html> 上的 data-* 属性以及 --nn-* CSS 变量共同组成。
基本接入
完整样式已经包含主题 Token:
import { createApp } from 'vue';
import NetNexusUi, { initializeTheme } from 'netnexus-ui';
import 'netnexus-ui/style.css';
import App from './App.vue';
initializeTheme();
createApp(App).use(NetNexusUi).mount('#app');只使用主题系统时,可以改为:
import { initializeTheme } from 'netnexus-ui/theme';
import 'netnexus-ui/theme.css';
initializeTheme();内置 preset
| 常量 | 值 | 解析后的明暗模式 | 说明 |
|---|---|---|---|
APP_THEME_PRESET.BLUE | blue | light | 默认 preset |
APP_THEME_PRESET.ORANGE | orange | light | 橙色品牌色 |
APP_THEME_PRESET.DARK | dark | dark | 深色主题 |
相关常量:
import {
APP_THEME,
APP_THEME_PRESET,
APP_THEME_PRESET_OPTIONS,
DEFAULT_THEME_PRESET,
THEME_PRESET_STORAGE_KEY
} from 'netnexus-ui/theme';DEFAULT_THEME_PRESET是blue。THEME_PRESET_STORAGE_KEY是netnexus.themePreset。APP_THEME_PRESET_OPTIONS提供“蓝色”“橙色”“深色”三个可直接渲染的选项。APP_THEME包含light和dark。
初始化后,管理器会维护以下 DOM 契约:
<html data-theme="light" data-theme-preset="blue" style="color-scheme: light"></html>深色 preset 对应:
<html data-theme="dark" data-theme-preset="dark" style="color-scheme: dark"></html>切换主题
默认管理器通过根入口和 netnexus-ui/theme 子入口同时导出。
<script setup>
import { APP_THEME_PRESET_OPTIONS, getThemeState, setThemePreset } from 'netnexus-ui/theme';
const { themePreset, resolvedTheme } = getThemeState();
</script>
<template>
<section>
<p>preset:{{ themePreset }};模式:{{ resolvedTheme }}</p>
<NnSpace>
<NnButton
v-for="option in APP_THEME_PRESET_OPTIONS"
:key="option.value"
:type="themePreset === option.value ? 'primary' : 'default'"
@click="setThemePreset(option.value)"
>
{{ option.label }}
</NnButton>
</NnSpace>
</section>
</template>setThemePreset() 默认把选择写入 localStorage。只应用一次、不覆盖本地选择时:
setThemePreset(APP_THEME_PRESET.DARK, { persistLocal: false });默认管理器 API:
| API | 行为 |
|---|---|
initializeTheme() | 从存储读取 preset、应用 DOM 属性并开始监听;返回停止监听的函数 |
setThemePreset(preset, options?) | 规范化并应用内置 preset;默认持久化 |
getThemeState() | 返回只读的 themePreset Ref 和 resolvedTheme ComputedRef |
disposeTheme() | 停止默认管理器的 Vue watcher |
isAppThemePreset(value) | 判断值是否为三个内置 preset 之一 |
normalizeThemePreset(value, fallback?) | 非法值回退到 fallback,默认回退到 blue |
getResolvedThemeFromPreset(preset) | dark 返回 dark,其他内置值返回 light |
disposeTheme() 只停止 watcher,不会删除 DOM 属性,也不会清除 localStorage。
独立主题管理器
需要自定义存储键、preset 或挂载目标时,使用 createThemeManager(),不要复用只接受内置 preset 的 setThemePreset()。
import { createThemeManager } from 'netnexus-ui/theme';
const brandTheme = createThemeManager({
presets: ['brand', 'night'],
defaultPreset: 'brand',
storageKey: 'my-app.theme',
resolveTheme: preset => (preset === 'night' ? 'dark' : 'light')
});
const stop = brandTheme.initialize();
brandTheme.setPreset('night');
// 保存 stop,并在应用真正不再使用该管理器时调用。配套 CSS:
html[data-theme-preset='brand'] {
--nn-color-primary: #7c3aed;
--nn-color-primary-hover: #8b5cf6;
--nn-color-primary-active: #6d28d9;
--nn-color-link: #7c3aed;
--nn-color-text-info: #6d28d9;
--nn-color-border-info: #a78bfa;
}
html[data-theme-preset='night'] {
--nn-color-primary: #c4b5fd;
--nn-color-primary-hover: #ddd6fe;
--nn-color-primary-active: #a78bfa;
}未覆盖的变量会继续使用基础亮色或深色值。要获得完整的品牌主题,应覆盖所有会影响目标界面的语义 Token,而不是依赖某个组件的内部选择器。
创建选项
| 选项 | 默认值 | 说明 |
|---|---|---|
presets | 三个内置 preset | 允许使用的字符串数组 |
defaultPreset | blue,或允许列表的第一项 | 存储为空或值非法时的回退值 |
storageKey | netnexus.themePreset | 持久化键名 |
storage | 浏览器 localStorage | 存储对象、返回存储对象的函数或 null |
target | document.documentElement | 具有 dataset 的对象、返回该对象的函数或 null |
resolveTheme | 内置 preset 解析函数 | 把 preset 映射为明暗模式;供内置 CSS 使用时应返回 light 或 dark |
实例 API
| 属性或方法 | 说明 |
|---|---|
themePreset | 当前 preset 的只读 Ref |
resolvedTheme | 解析后模式的只读 ComputedRef |
initialize() | 读取存储、应用主题、启动 watcher,并返回 dispose |
setPreset(preset, options?) | 切换主题;persistLocal: false 可跳过写入 |
apply() | 立即把当前状态重新应用到 target |
dispose() | 停止 watcher |
自定义存储对象至少需要 getItem(key) 和 setItem(key, value)。读写失败时当前实现会输出警告并继续使用内存中的状态。
CSS Token
src/styles/theme.css 当前定义 110 个不同的 --nn-* 变量。值会随 preset 变化,以下按用途列出公开名称;实际值和选择器顺序以源码为准。
字体与基础语义色
--nn-font-family
--nn-color-primary
--nn-color-primary-hover
--nn-color-primary-active
--nn-color-link
--nn-color-success
--nn-color-warning
--nn-color-error
--nn-color-info背景色
--nn-color-bg-body
--nn-color-bg-layout
--nn-color-bg-surface
--nn-color-bg-elevated
--nn-color-bg-muted
--nn-color-bg-subtle
--nn-color-bg-hover
--nn-color-bg-disabled
--nn-color-bg-code
--nn-color-bg-selected
--nn-color-bg-info-subtle
--nn-color-bg-success-subtle
--nn-color-bg-warning-subtle
--nn-color-bg-stale
--nn-color-bg-danger-subtle
--nn-color-bg-progress
--nn-color-bg-console
--nn-color-bg-console-muted
--nn-color-bg-console-success
--nn-color-bg-console-info
--nn-color-bg-console-error
--nn-color-bg-sider
--nn-color-bg-sider-hover
--nn-color-bg-sider-active
--nn-color-bg-card-head
--nn-color-bg-card-head-hover
--nn-color-bg-card-head-control
--nn-color-bg-card-head-control-hover
--nn-color-bg-card-head-ghost
--nn-color-bg-card-head-ghost-hover
--nn-color-overlay-mask文本色
--nn-color-text
--nn-color-text-strong
--nn-color-text-secondary
--nn-color-text-muted
--nn-color-text-placeholder
--nn-color-text-disabled
--nn-color-text-inverse
--nn-color-text-sider
--nn-color-text-info
--nn-color-text-success
--nn-color-text-warning
--nn-color-text-stale
--nn-color-text-card-head-control
--nn-color-text-card-head-ghost
--nn-color-text-console
--nn-color-text-console-muted
--nn-color-text-console-label
--nn-color-text-console-success
--nn-color-text-console-success-strong
--nn-color-text-console-info
--nn-color-text-console-info-strong
--nn-color-text-console-error
--nn-color-text-console-error-strong边框与 Tooltip
--nn-color-border
--nn-color-border-light
--nn-color-border-info
--nn-color-border-danger
--nn-color-border-sider
--nn-color-border-sider-active
--nn-color-border-card-head-control
--nn-color-border-card-head-ghost
--nn-color-tooltip-bg
--nn-color-tooltip-text语法高亮
--nn-color-syntax-tag
--nn-color-syntax-attribute
--nn-color-syntax-value
--nn-color-syntax-comment
--nn-color-syntax-declaration
--nn-color-syntax-cdata
--nn-color-syntax-entity
--nn-color-syntax-punctuation终端配色
终端 token 独立于通用 Console token,包含背景、前景、光标、选区和完整 ANSI 16 色;这样浅色 preset 可以提供浅色终端,而日志 Console 仍可保持深色外观。
--nn-color-terminal-background
--nn-color-terminal-foreground
--nn-color-terminal-cursor
--nn-color-terminal-selection-background
--nn-color-terminal-ansi-black
--nn-color-terminal-ansi-red
--nn-color-terminal-ansi-green
--nn-color-terminal-ansi-yellow
--nn-color-terminal-ansi-blue
--nn-color-terminal-ansi-magenta
--nn-color-terminal-ansi-cyan
--nn-color-terminal-ansi-white
--nn-color-terminal-ansi-bright-black
--nn-color-terminal-ansi-bright-red
--nn-color-terminal-ansi-bright-green
--nn-color-terminal-ansi-bright-yellow
--nn-color-terminal-ansi-bright-blue
--nn-color-terminal-ansi-bright-magenta
--nn-color-terminal-ansi-bright-cyan
--nn-color-terminal-ansi-bright-white扁平化兼容令牌
以下名称为兼容既有主题而保留。内置主题中阴影与旧焦点光晕均为 none,两个 gradient 名称解析为纯色;新主题不应重新引入悬浮阴影或渐变。
--nn-shadow-sider
--nn-shadow-elevated
--nn-shadow-floating
--nn-shadow-floating-hover
--nn-shadow-card-head-control
--nn-focus-shadow-error
--nn-focus-shadow-primary
--nn-gradient-panel
--nn-gradient-progress已知边界
- 默认管理器只接受
blue、orange、dark;自定义 preset 必须使用独立管理器。 - 管理器没有监听浏览器的
storage事件,不会自动同步其他标签页中的主题变化。 - 服务端没有
window或document时,默认 storage 和 target 都是null,调用不会写 DOM;客户端挂载时仍需再次初始化。 - 保存过的非默认主题要等 JavaScript 初始化后才会写入 DOM。对首屏颜色切换敏感的应用应尽早调用
initializeTheme()。 dispose()不清理属性或存储;如需恢复,应先切换到目标 preset,再停止监听。- 自定义
resolveTheme的返回值会直接写入data-theme和style.colorScheme。使用内置 CSS 时应返回有效的light或dark。
