refactor: 样式调整和代码优化

This commit is contained in:
Ray.Hao
2025-10-06 14:02:15 +08:00
parent dbb43bc57e
commit e743d04375
21 changed files with 177 additions and 891 deletions

View File

@@ -1,311 +0,0 @@
# 主题系统使用指南
## 概述
本项目基于 Wot Design Uni 的 ConfigProvider 组件实现了完整的主题系统,支持:
- 🌙 暗黑/浅色模式切换
- 🎨 12种预设主题色
- 🎯 自定义主题色
- 💾 主题设置持久化存储
- 📱 多平台兼容H5、小程序
## 核心文件
### 1. useTheme Composable (`src/composables/useTheme.ts`)
主题管理的核心逻辑,提供:
```typescript
const {
theme, // 当前主题模式 'light' | 'dark'
themeVars, // ConfigProviderThemeVars 主题变量
toggleTheme, // 切换主题模式
setThemeColor, // 设置主题色
resetTheme, // 重置主题
initTheme, // 初始化主题
colorColumns, // 预设主题色列表
} = useTheme();
```
### 2. 布局文件
#### Tabbar 布局 (`src/layouts/tabbar.vue`)
```vue
<template>
<wd-config-provider
:theme="theme"
:theme-vars="themeVars"
custom-style="min-height: 100vh"
:class="{ 'wot-theme-dark': theme === 'dark' }"
>
<!-- 页面内容 -->
</wd-config-provider>
</template>
```
#### Default 布局 (`src/layouts/default.vue`)
```vue
<template>
<wd-config-provider
:theme="theme"
:theme-vars="themeVars"
custom-style="background-color: #f5f5f5;min-height: 100vh"
:class="{ 'wot-theme-dark': theme === 'dark' }"
>
<!-- 页面内容 -->
</wd-config-provider>
</template>
```
### 3. 主题设置页面 (`src/pages/mine/settings/theme/index.vue`)
提供用户界面来:
- 切换暗黑/浅色模式
- 选择预设主题色
- 输入自定义主题色
- 预览主题效果
- 重置主题设置
## 主题变量
### 支持的 ConfigProviderThemeVars
根据 Wot Design Uni 文档,主要使用:
```typescript
interface ConfigProviderThemeVars {
colorTheme?: string; // 主题色
buttonPrimaryBgColor?: string; // 主按钮背景色
buttonPrimaryColor?: string; // 主按钮文字色
// ... 更多变量
}
```
### 预设主题色
```typescript
const colorColumns = [
{ value: "#165DFF", label: "蓝色" },
{ value: "#0FC6C2", label: "青绿色" },
{ value: "#722ED1", label: "紫色" },
{ value: "#F5222D", label: "红色" },
{ value: "#FA8C16", label: "橙色" },
{ value: "#FADB14", label: "黄色" },
{ value: "#52C41A", label: "绿色" },
{ value: "#EB2F96", label: "粉色" },
{ value: "#13C2C2", label: "青色" },
{ value: "#1890FF", label: "天蓝色" },
{ value: "#CD5C5C", label: "经典红" },
{ value: "#228B22", label: "自然绿" },
];
```
## 暗黑模式实现
### 1. ConfigProvider 主题切换
```vue
<wd-config-provider :theme="theme">
<!-- theme 'dark' 时自动应用暗黑模式 -->
</wd-config-provider>
```
### 2. 全局样式适配
`src/uni.scss` 中定义:
```scss
.wot-theme-dark {
background-color: #1a1a1a !important;
color: #f5f5f5 !important;
/* H5 环境 body 样式 */
body {
background-color: #1a1a1a !important;
color: #f5f5f5 !important;
}
/* 其他组件暗黑模式适配 */
}
```
### 3. 动态 Body 样式
`useTheme` 中自动处理:
```typescript
const applyDarkModeBodyStyle = (isDark: boolean) => {
// #ifdef H5
if (typeof document !== "undefined") {
const body = document.body;
if (isDark) {
body.style.backgroundColor = "#1a1a1a";
body.style.color = "#f5f5f5";
body.classList.add("wot-theme-dark");
} else {
body.style.backgroundColor = "#f8f8f8";
body.style.color = "#333";
body.classList.remove("wot-theme-dark");
}
}
// #endif
};
```
## 持久化存储
主题设置自动保存到本地存储:
```typescript
// 存储键名
const THEME_STORAGE_KEY = "app_theme_mode";
const THEME_COLOR_STORAGE_KEY = "app_theme_color";
// 自动监听变化并保存
watch(
theme,
(newTheme) => {
saveThemeToStorage(newTheme);
applyDarkModeBodyStyle(newTheme === "dark");
},
{ immediate: true }
);
```
## 使用示例
### 在页面中使用主题
```vue
<template>
<view>
<wd-button type="primary">主题色按钮</wd-button>
<text :style="{ color: themeVars.colorTheme }">主题色文本</text>
</view>
</template>
<script setup>
import { useTheme } from "@/composables/useTheme";
const { theme, themeVars, toggleTheme, setThemeColor } = useTheme();
// 切换主题模式
const handleToggleTheme = () => {
toggleTheme();
};
// 设置主题色
const handleSetColor = (color: string) => {
setThemeColor(color);
};
</script>
```
### 在组件中响应主题变化
```vue
<template>
<view :class="{ 'dark-mode': isDark }">
<!-- 组件内容 -->
</view>
</template>
<script setup>
import { computed } from "vue";
import { useTheme } from "@/composables/useTheme";
const { theme } = useTheme();
const isDark = computed(() => theme.value === "dark");
</script>
<style>
.dark-mode {
background-color: #2a2a2a;
color: #f5f5f5;
}
</style>
```
## 最佳实践
### 1. 组件开发
- 使用 Wot Design Uni 组件时,主题色会自动应用
- 自定义组件需要手动适配暗黑模式
- 使用 `:class="{ 'wot-theme-dark': theme === 'dark' }"` 来应用暗黑模式样式
### 2. 样式编写
```scss
.my-component {
background-color: #fff;
color: #333;
// 暗黑模式适配
.wot-theme-dark & {
background-color: #2a2a2a;
color: #f5f5f5;
}
}
```
### 3. 主题色使用
```vue
<template>
<!-- 直接使用主题色 -->
<view :style="{ borderColor: themeVars.colorTheme }">
<!-- 内容 -->
</view>
</template>
```
## 注意事项
1. **ConfigProvider 包裹**:确保页面被 ConfigProvider 包裹才能应用主题
2. **样式优先级**:暗黑模式样式需要足够的优先级,必要时使用 `!important`
3. **平台兼容**:小程序和 H5 的样式处理略有不同,使用条件编译处理
4. **性能考虑**:主题切换时避免频繁的 DOM 操作
## 扩展功能
### 添加新的主题色
`colorColumns` 中添加新的颜色:
```typescript
export const colorColumns = [
// ... 现有颜色
{ value: "#FF6B6B", label: "珊瑚红" },
{ value: "#4ECDC4", label: "薄荷绿" },
];
```
### 添加更多主题变量
```typescript
const themeVars = ref<ConfigProviderThemeVars>({
colorTheme: getStoredThemeColor(),
buttonPrimaryBgColor: getStoredThemeColor(),
// 添加更多变量
});
```
### 自定义暗黑模式样式
`uni.scss` 中添加更多组件的暗黑模式适配:
```scss
.wot-theme-dark {
// 新组件的暗黑模式样式
.my-custom-component {
background-color: #2a2a2a;
color: #f5f5f5;
}
}
```

View File

@@ -1,426 +0,0 @@
# uni-mini-router 在UniApp中的整合教程
## 一、uni-mini-router简介
uni-mini-router是一个轻量级的路由管理库专为uni-app设计解决了uni-app原生路由系统中没有路由拦截等关键功能的问题。它提供了类似Vue Router的API体验使得在uni-app项目中实现更加灵活和强大的路由管理成为可能。
### 主要特点:
1. **Vue Router风格API**提供与Vue Router相似的API降低学习成本
2. **路由拦截功能**:支持全局导航守卫,可以在路由跳转前后执行逻辑
3. **优雅的参数传递**支持params和query方式传参
4. **命名路由**:支持通过路由名称进行导航
5. **类型支持**完整的TypeScript类型定义
6. **轻量级**:体积小,性能高效
## 二、安装与基本配置
### 1. 安装uni-mini-router
使用npm或yarn安装uni-mini-router
```bash
pnpm add - uni-mini-router
```
### 2. 初始化路由
在项目中创建router目录并初始化路由配置
```typescript
// src/router/index.ts
import { createRouter } from 'uni-mini-router'
import { pages, subPackages } from 'virtual:uni-pages'
// 生成路由配置
function generateRoutes() {
const routes = pages.map((page) => {
const newPath = `/${page.path}`
return { ...page, path: newPath }
})
// 处理分包路由
if (subPackages && subPackages.length > 0) {
subPackages.forEach((subPackage) => {
const subRoutes = subPackage.pages.map((page: any) => {
const newPath = `/${subPackage.root}/${page.path}`
return { ...page, path: newPath }
})
routes.push(...subRoutes)
})
}
return routes
}
// 创建路由实例
const router = createRouter({
routes: generateRoutes(),
})
export default router
```
### 3. 在main.ts中挂载路由
```typescript
// src/main.ts
import { createSSRApp } from 'vue'
import App from './App.vue'
import router from './router'
export function createApp() {
const app = createSSRApp(App)
// 使用路由
app.use(router)
return {
app
}
}
```
### 4. 配置自动导入(可选,推荐)
使用unplugin-auto-import插件可以自动导入路由相关hooks无需每次手动导入
```typescript
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
imports: [
'vue',
{
from: 'uni-mini-router',
imports: ['createRouter', 'useRouter', 'useRoute']
}
],
dts: 'src/auto-imports.d.ts'
})
]
})
```
## 三、路由基本用法
### 1. 编程式导航
uni-mini-router提供了多种导航方法
```typescript
const router = useRouter()
// 字符串路径导航
router.push('/pages/index/index')
// 对象导航(通过路径)
router.push({ path: '/pages/index/index' })
// 对象导航(通过名称)
router.push({ name: 'index' })
// 携带参数
router.push({
path: '/pages/detail/index',
query: { id: 10 }
})
// 通过名称 + 参数
router.push({
name: 'detail',
params: { id: 10 }
})
// Tab页面导航
router.pushTab('/pages/home/index')
// 关闭当前页面并跳转
router.replace('/pages/index/index')
// 关闭所有页面并跳转
router.replaceAll('/pages/index/index')
// 返回上一级
router.back()
// 返回多级
router.back(2)
```
### 2. 获取和使用路由信息
```typescript
const route = useRoute()
// 访问当前路由信息
console.log(route.path) // 当前路由路径
console.log(route.name) // 当前路由名称
console.log(route.query) // 查询参数
console.log(route.params) // 路由参数
```
### 3. 接收页面参数
在页面组件中接收传递的参数:
```typescript
<script setup lang="ts">
const route = useRoute()
const router = useRouter()
// 方法1: 直接从route对象获取
const id = route.query.id || route.params.id
// 方法2: 通过onLoad生命周期获取
onLoad((option) => {
console.log('页面参数:', option)
// option中包含所有传递的参数
})
</script>
```
> ⚠️ **重要说明**在uni-mini-router中params和query参数都会转换为查询字符串放在URL中两者在实际效果上没有区别。这种设计是为了与Vue Router保持API一致性。
## 四、导航守卫
uni-mini-router提供了全局导航守卫功能可以在路由跳转前后执行自定义逻辑。
### 1. 全局前置守卫
```typescript
// src/router/index.ts
router.beforeEach((to, from, next) => {
console.log('路由跳转:', from.path, '->', to.path)
// 检查是否需要登录
if (to.meta && to.meta.requireAuth) {
// 检查登录状态
const isLoggedIn = uni.getStorageSync('token')
if (!isLoggedIn) {
// 未登录,跳转到登录页
uni.showToast({ title: '请先登录', icon: 'none' })
next('/pages/login/index')
return
}
}
// 继续导航
next()
})
```
### 2. 全局后置守卫
```typescript
// src/router/index.ts
router.afterEach((to, from) => {
console.log('路由跳转完成:', to.path)
// 可以在这里做一些统计或记录
})
```
### 3. 路由元数据配置
可以在页面文件中使用`<route>`自定义块来定义路由元数据:
```vue
<template>
<!-- 页面内容 -->
</template>
<script setup>
// 页面逻辑
</script>
<route lang="json">
{
"name": "protected-page",
"meta": {
"requireAuth": true,
"title": "需要登录的页面"
}
}
</route>
```
## 五、实战示例:登录权限控制
### 1. 定义带有权限控制的路由
```typescript
// src/router/index.ts
import { createRouter } from 'uni-mini-router'
const router = createRouter({
routes: generateRoutes()
})
// 全局前置守卫
router.beforeEach((to, from, next) => {
// 检查页面是否需要登录
if (to.meta && to.meta.requireAuth) {
const token = uni.getStorageSync('token')
if (!token) {
// 显示登录提示
uni.showModal({
title: '提示',
content: '该功能需要登录后使用',
confirmText: '去登录',
cancelText: '返回',
success: (res) => {
if (res.confirm) {
// 记住原来要去的页面
uni.setStorageSync('redirect', to.fullPath)
next('/pages/login/index')
} else {
// 取消则返回首页
next('/pages/index/index')
}
}
})
return
}
}
// 继续导航
next()
})
export default router
```
### 2. 登录成功后跳转回原页面
```vue
<!-- src/pages/login/index.vue -->
<script setup>
const router = useRouter()
function handleLogin() {
// 模拟登录请求
setTimeout(() => {
// 登录成功存储token
uni.setStorageSync('token', 'user_token_example')
// 获取之前要去的页面
const redirect = uni.getStorageSync('redirect') || '/pages/index/index'
uni.removeStorageSync('redirect')
// 跳转回原来的页面
router.replaceAll(redirect)
}, 1000)
}
</script>
```
## 六、最佳实践与性能优化
### 1. 合理使用跳转方式
- **router.push**:需要保留当前页面、可返回时使用
- **router.replace**:不需要返回当前页面时使用
- **router.replaceAll**:需要清除所有页面栈时使用(如登录后)
- **router.pushTab**跳转到tabBar页面时使用
### 2. 参数传递最佳实践
- 对于简单数据,直接使用参数传递
- 对于复杂数据或对象,可使用以下方法:
```typescript
// 传递复杂对象
const complexData = { name: 'product', details: { id: 1, features: ['a', 'b'] } }
// 方法1: JSON序列化 + URL编码
router.push({
path: '/pages/detail/index',
query: { data: encodeURIComponent(JSON.stringify(complexData)) }
})
// 接收页面
onLoad((option) => {
if (option.data) {
try {
const data = JSON.parse(decodeURIComponent(option.data))
console.log(data)
} catch (e) {
console.error('参数解析错误', e)
}
}
})
// 方法2: 对于非常大的数据,考虑使用全局状态管理或本地存储
```
### 3. 路由懒加载
uni-mini-router自动支持小程序的分包加载特性可以在pages.json中配置分包
```json
{
"pages": [
// 主包页面
],
"subPackages": [
{
"root": "pages/module",
"pages": [
{
"path": "detail/index",
"style": {
"navigationBarTitleText": "详情页"
}
}
]
}
]
}
```
## 七、路由调试与测试
### 1. 路由日志记录
```typescript
// src/router/index.ts
router.beforeEach((to, from, next) => {
console.log(`[Router] ${from.path || '初始页面'} -> ${to.path}`, {
params: to.params,
query: to.query,
})
next()
})
```
### 2. 常见问题解决
1. **路由参数获取不到**
- 检查传参方式是否正确
- 使用`console.log`打印完整的option对象
- 尝试同时检查route.query和route.params
2. **页面未注册**
- 确保页面已在pages.json中正确注册
- 检查路径大小写是否正确
3. **导航守卫不生效**
- 确保在路由配置后调用守卫
- 检查是否正确调用next()函数
## 总结
uni-mini-router为uni-app提供了Vue Router风格的路由解决方案特别是增加了路由拦截功能解决了uni-app原生路由的限制。通过简单配置就能在uni-app中实现更加灵活的路由管理包括权限控制、参数传递和路由拦截等高级功能。
使用uni-mini-router可以让你的uni-app项目路由管理更加规范化和工程化提升开发效率和代码质量。
参考资料:
- [uni-mini-router GitHub仓库](https://github.com/Moonofweisheng/uni-mini-router)
- [uni-mini-router官方文档](https://moonofweisheng.github.io/uni-mini-router/)
- [uni-app官方路由文档](https://uniapp.dcloud.net.cn/tutorial/page.html)