159 lines
4.2 KiB
Markdown
159 lines
4.2 KiB
Markdown
# 9.14 样式与主题定制
|
||
|
||
:::tip 概述
|
||
前端使用 WindiCSS + Less 实现样式管理,基于 `@zougt/vite-plugin-theme-preprocessor` 支持主题切换和暗色模式。
|
||
:::
|
||
|
||
## 技术栈
|
||
|
||
| 技术 | 用途 |
|
||
|------|------|
|
||
| WindiCSS | 原子化 CSS 框架(`vite-plugin-windicss`,兼容 Tailwind 语法) |
|
||
| Less | 全局样式变量和主题 |
|
||
| Ant Design 主题变量 | 组件样式覆盖(`@primary-color` 等 Less 变量) |
|
||
|
||
## 全局样式文件
|
||
|
||
```text
|
||
ui/src/styles/
|
||
├── index.less # 全局样式入口(@import 子模块)
|
||
├── color.less # 颜色变量定义(@white、@content-bg、--content-bg 等)
|
||
├── common.less # 公共样式类
|
||
├── config.less # 配置引用(@import (reference) 'color.less')
|
||
├── tailwind.css # Tailwind 兼容指令入口(由 WindiCSS 处理)
|
||
├── theme/
|
||
│ ├── theme-default.less # 默认主题(引入 Ant Design 默认 Less 主题)
|
||
│ └── theme-dark.less # 暗色主题(引入 Ant Design 暗色 Less 主题)
|
||
└── transition/
|
||
├── index.less # 过渡动画入口
|
||
├── base.less / fade.less / scale.less / slide.less / zoom.less / scroll.less
|
||
```
|
||
|
||
## Less 变量
|
||
|
||
```less
|
||
/* ui/src/styles/color.less */
|
||
html {
|
||
--content-bg: #f0f2f5;
|
||
}
|
||
|
||
@white: #fff;
|
||
@content-bg: #f0f2f5;
|
||
```
|
||
|
||
Ant Design 组件主题通过标准 Less 变量覆盖,例如主色:
|
||
|
||
```less
|
||
/* 覆盖主色示例 */
|
||
@primary-color: #165DFF;
|
||
```
|
||
|
||
## 主题切换
|
||
|
||
主题切换基于 `@zougt/vite-plugin-theme-preprocessor`,两套主题文件在构建时编译为独立作用域样式,运行时通过 `toggleTheme` 切换:
|
||
|
||
```typescript
|
||
// build/vite/plugin/theme.ts
|
||
import themePreprocessorPlugin from '@zougt/vite-plugin-theme-preprocessor';
|
||
|
||
export function configThemePlugin(): Plugin[] {
|
||
return [
|
||
themePreprocessorPlugin({
|
||
themeScopes: [
|
||
{
|
||
scopeName: 'theme-default',
|
||
path: path.resolve('src/styles/theme/theme-default.less'),
|
||
},
|
||
{
|
||
scopeName: 'theme-dark',
|
||
path: path.resolve('src/styles/theme/theme-dark.less'),
|
||
},
|
||
],
|
||
}),
|
||
];
|
||
}
|
||
```
|
||
|
||
页面中通过「项目配置」抽屉切换明暗主题:
|
||
|
||
```typescript
|
||
// ui/src/layout/components/Header/ProjectSetting.vue
|
||
import { toggleTheme } from '@zougt/vite-plugin-theme-preprocessor/dist/browser-utils';
|
||
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||
|
||
const settingStore = useProjectSettingStore();
|
||
|
||
function handleToggleTheme(theme: string) {
|
||
const isDark = theme === 'darkness';
|
||
settingStore.darkTheme = isDark;
|
||
updateDarkTheme(isDark ? 'dark' : 'light');
|
||
}
|
||
|
||
async function updateDarkTheme(mode: 'light' | 'dark') {
|
||
toggleTheme({ scopeName: mode === 'dark' ? 'theme-dark' : 'theme-default' });
|
||
}
|
||
```
|
||
|
||
主题状态由 Pinia 的 `projectSetting` Store 管理(`darkTheme`、`navTheme`、`headerTheme`)。
|
||
|
||
## 主题文件
|
||
|
||
```less
|
||
/* ui/src/styles/theme/theme-default.less */
|
||
@import "ant-design-vue/lib/style/themes/default.less";
|
||
|
||
/* ui/src/styles/theme/theme-dark.less */
|
||
@import "ant-design-vue/lib/style/themes/dark.less";
|
||
```
|
||
|
||
自定义组件覆盖直接追加在对应主题文件中,通过生成的作用域类(`.theme-default` / `.theme-dark`)区分明暗模式。
|
||
|
||
## WindiCSS 配置
|
||
|
||
```typescript
|
||
// ui/windi.config.ts
|
||
import { defineConfig } from 'vite-plugin-windicss';
|
||
|
||
export default defineConfig({
|
||
darkMode: 'class',
|
||
plugins: [createEnterPlugin()],
|
||
theme: {
|
||
extend: {
|
||
zIndex: { '-1': '-1' },
|
||
screens: {
|
||
sm: '576px',
|
||
md: '768px',
|
||
lg: '992px',
|
||
xl: '1200px',
|
||
'2xl': '1600px',
|
||
},
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
:::tip 说明
|
||
项目使用 `vite-plugin-windicss`,类名语法与 TailwindCSS 兼容(`class="flex items-center justify-between"`),但配置文件是 `windi.config.ts` 而非 `tailwind.config.js`。
|
||
:::
|
||
|
||
## 自定义全局样式
|
||
|
||
```less
|
||
/* ui/src/styles/common.less */
|
||
|
||
// 页面容器
|
||
.page-container {
|
||
padding: 16px;
|
||
background: var(--content-bg);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
// 搜索表单
|
||
.search-form {
|
||
margin-bottom: 16px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
border-radius: 4px;
|
||
}
|
||
```
|