Skip to content

多主题与主题切换

23:52

概述

项目内置了完整的多主题支持系统,包括亮色主题和深色主题。用户可以根据系统设置或手动选择,实时切换应用的颜色主题,提供更好的用户体验。

项目特性

  • 🎨 亮色/深色主题 - 内置亮色和深色两个主题
  • 🔄 实时切换 - 无需刷新页面,即时切换主题
  • 💾 记住偏好 - 主题选择会自动保存
  • 🌈 自定义配置 - 轻松扩展和自定义主题颜色
  • 📱 系统适配 - 支持跟随系统主题设置

主题配置文件

theme.json 配置

src/theme.json 定义了应用的主题颜色:

json
{
  "light": {
    "bgColor": "#fcfcfc",              // 背景颜色
    "bgColorBottom": "#fcfcfc",        // 底部背景
    "bgColorTop": "#ff6b00",           // 顶部背景
    "bgTxtStyle": "dark",              // 背景上的文字样式
    "navBgColor": "#ff6b00",           // 导航栏背景
    "navTxtStyle": "white",            // 导航栏文字样式
    "tabBgColor": "#fcfcfc",           // Tabbar 背景
    "tabBorderStyle": "black",         // Tabbar 边框样式
    "tabFontColor": "#1f2937",         // Tabbar 文字颜色
    "tabSelectedColor": "#ff6b00"      // Tabbar 选中颜色
  },
  "dark": {
    "bgColor": "#181818",
    "bgColorBottom": "#181818",
    "bgColorTop": "#ff6b00",
    "bgTxtStyle": "light",
    "navBgColor": "#ff6b00",
    "navTxtStyle": "white",
    "tabBgColor": "#181818",
    "tabBorderStyle": "white",
    "tabFontColor": "#f3f4f6",
    "tabSelectedColor": "#ff6b00"
  }
}

uView Pro 主题配置

src/common/uview-pro.theme.ts 定义了 uView Pro 组件库的主题:

typescript
// 此文件定义 uView Pro 组件库的多个主题
// 默认主题为 'green',可在 main.ts 中修改
export default {
  green: {
    // primary 主题色
    primary: '#07c160',
    // 其他主题颜色...
  },
  // 其他主题定义...
}

初始化设置

main.ts 中的注册主题

typescript
import themes from '@/common/uview-pro.theme'
import uViewPro from 'uview-pro'

app.use(uViewPro, {
  theme: {
    themes,
    defaultTheme: 'green',      // 默认主题名称
    defaultDarkMode: 'light',   // 默认暗黑模式('light'|'dark'|'auto')
  }
})

pages.json 中的主题应用

json
{
  "globalStyle": {
    "backgroundColor": "@bgColor",
    "backgroundColorBottom": "@bgColorBottom",
    "backgroundColorTop": "@bgColorTop",
    "backgroundTextStyle": "@bgTxtStyle",
    "navigationBarBackgroundColor": "#000000",
    "navigationBarTextStyle": "@navTxtStyle"
  }
}

基本使用

在组件中切换主题

vue
<script setup lang="ts">
import { useTheme } from 'uview-pro'

const { darkMode, getAvailableThemes, currentTheme, setTheme, toggleDarkMode } = useTheme()

const themeNames = getAvailableThemes().map(theme => theme.name)
function handleThemeToggle() {
  setTheme(themeNames[Math.floor(Math.random() * themeNames.length)])
}
function handleDarkModeToggle() {
  toggleDarkMode()
}
</script>

<template>
  <view class="theme-switcher">
    <text>当前主题:{{ currentTheme?.label }}</text>
    <u-button type="primary" @click="handleThemeToggle">
      切换主题
    </u-button>
    <text>当前暗黑主题:{{ darkMode }}</text>
    <u-button type="primary" @click="handleDarkModeToggle">
      切换暗黑主题
    </u-button>
  </view>
</template>

根据主题条件渲染

vue
<script setup lang="ts">
import { useTheme } from 'uview-pro'

const { darkMode } = useTheme()
</script>

<template>
  <view v-if="darkMode === 'light'" class="light-theme">
    亮色主题内容
  </view>
  <view v-else class="dark-theme">
    深色主题内容
  </view>
</template>

高级用法

自定义单主题颜色

修改系统主题的颜色色值:

typescript
import uViewPro from 'uview-pro'

app.use(uViewPro, {
  theme: {
    primary: '#9c27b0',
    success: '#07c160',
    warning: '#fa8919',
    danger: '#ff5252',
    error: '#ff5252',
    info: '#909399',
  }
})

自定义多主题颜色

扩展 src/common/uview-pro.theme.ts

typescript
export default {
  // 绿色主题
  green: {
    primary: '#07c160',
    success: '#07c160',
    warning: '#fa8919',
    danger: '#ff5252',
    error: '#ff5252',
    info: '#909399',
  },
  
  // 橙色主题
  orange: {
    primary: '#ff6b00',
    success: '#07c160',
    warning: '#fa8919',
    danger: '#ff5252',
    error: '#ff5252',
    info: '#909399',
  },
  
  // 蓝色主题
  blue: {
    primary: '#3498db',
    success: '#07c160',
    warning: '#fa8919',
    danger: '#ff5252',
    error: '#ff5252',
    info: '#909399',
  },
  
  // 紫色主题
  purple: {
    primary: '#9c27b0',
    success: '#07c160',
    warning: '#fa8919',
    danger: '#ff5252',
    error: '#ff5252',
    info: '#909399',
  },
}

然后在 main.ts 中的注册主题

typescript
import themes from '@/common/uview-pro.theme'
import uViewPro from 'uview-pro'

app.use(uViewPro, {
  theme: {
    themes,
    defaultTheme: 'green',      // 默认主题名称
    defaultDarkMode: 'light',   // 默认暗黑模式('light'|'dark'|'auto')
  }
})

主题选择界面

vue
<script setup lang="ts">
import type { DarkMode } from 'uview-pro/types/global'
import { useTheme } from 'uview-pro'
import { ref } from 'vue'

const { darkMode, currentTheme, setDarkMode, setTheme, getAvailableThemes } = useTheme()

const darkModes = ref<{ value: DarkMode, label: string }[]>(
  [
    { value: 'auto', label: '自动' },
    { value: 'light', label: '亮色' },
    { value: 'dark', label: '深色' },
  ],
)
function handleThemeSelect(theme: string) {
  // 切换到选定的主题
  setTheme(theme)
}

function handleDarkModeSelect(mode: DarkMode) {
  setDarkMode(mode)
}
</script>

<template>
  <view class="theme-settings">
    <view class="section">
      <text class="title">
        主题选择
      </text>
      <view class="theme-grid">
        <view
          v-for="theme in getAvailableThemes()" 
          :key="theme.name" class="theme-item"
          @click="handleThemeSelect(theme.name)"
        >
          <view class="color-box" :style="{ 'background-color': theme.color.primary }">
            <u-icon v-if="currentTheme?.name === theme.name" name="checkbox-mark" />
          </view>
          <text>{{ theme.label }}</text>
        </view>
      </view>
    </view>

    <view class="section">
      <text class="title">
        暗黑模式选择
      </text>
      <view class="mode-list">
        <view
          v-for="mode in darkModes" 
          :key="mode.value" class="mode-item" 
          :class="{ active: darkMode === mode.value }"
          @click="handleDarkModeSelect(mode.value)"
        >
          <text>{{ mode.label }}</text>
          <u-icon v-if="darkMode === mode.value" name="checkbox-mark" />
        </view>
      </view>
    </view>
  </view>
</template>

<style scoped lang="scss">
.theme-settings {
  padding: 16px;

  .section {
    margin-bottom: 24px;
  }

  .title {
    display: block;
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 12px;
  }

  .theme-grid {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
  }

  .theme-item {
    text-align: center;

    .color-box {
      width: 48px;
      height: 48px;
      border-radius: 8px;
      margin-bottom: 8px;
      background-color: var(--u-type-primary);
      color: white;
      display: flex;
      justify-content: center;
    }

    text {
      font-size: 12px;
    }
  }

  .mode-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .mode-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px;
    border: 1px solid var(--u-border-color);
    border-radius: 8px;
    transition: all 0.3s;

    &.active {
      background-color: var(--u-type-primary);
      color: white;
      border-color: var(--u-type-primary);
    }
  }
}
</style>

最佳实践

  1. 颜色一致性 - 确保所有主题中的颜色使用一致且具有良好的对比度
  2. 可访问性 - 考虑色盲用户,避免仅用颜色区分内容
  3. 性能优化 - 使用 CSS 变量而不是动态计算主题颜色
  4. 默认选择 - 根据用户的系统设置选择默认主题
  5. 过渡效果 - 为主题切换添加平滑的过渡动画
  6. 测试覆盖 - 在所有主题下测试应用外观和功能
  7. 文档化 - 记录主题色值和使用规则

常见问题

主题切换不生效

检查:

  1. 确认在main.ts中注册了uViewPro及多主题
  2. 确认已经使用u-config-provider来包裹所有页面
  3. 确认主题配置已正确加载
  4. 检查样式是否正确应用

深色模式下文字不清晰

调整 CSS 变量中的文字颜色,确保足够的对比度。

如何添加新主题?

src/common/uview-pro.theme.ts 中添加新的主题定义,然后在应用中选择使用。

相关文档