注:当前为我自己项目经验的方案,如果大家有更好的希望可以在评论区告诉我
安装pinia-plugin-persistedstate
npm i pinia-plugin-persistedstate
配置pinia-plugin-persistedstate
//main.js文件
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
import {
createPinia
} from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export function createApp() {
const app = createSSRApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
return {
app,
pinia
}
}
// #endif
配置主题管理pinia全局缓存文件
// stores/theme.js
import { defineStore } from 'pinia'
import { ref, computed, watch } from 'vue'
export const useThemeStore = defineStore('theme', () => {
// 当前主题名称
const themeName = ref('KFC')
// 添加一个标记,表示主题是否已初始化
const isThemeInitialized = ref(false)
// 主题配置映射
// --dominant-color:如主背景色、按钮颜色、提示性文字色,金额
// --text-color:标题、正文信息颜色
// --text-secondary:标题、正文信息颜色
// --text-auxiliary:用于辅助、次要级信息颜色
// --bg-color:背景色
// --border-color:边框颜色
// --dividing-line:分割线颜色
// --card-bg:卡片背景色
// --mask-bg:遮罩背景色
// --shadow-color:阴影颜色
const themeConfig = ref({
KFC: {
name: 'KFC',
'--primary-color': '#007aff',
'--secondary-color': '#5856d6',
'--success-color': '#4cd964',
'--warning-color': '#ff9500',
'--danger-color': '#ff3b30',
'--dominant-color': '#E40031',
'--bg-color': '#E40031',
'--text-color': '#222222',
'--text-secondary': '#666666',
'--text-auxiliary': '#999999',
'--border-color': '#e0e0e0',
'--card-bg': '#ffffff',
'--mask-bg': 'rgba(0, 0, 0, 0.4)',
'--shadow-color': 'rgba(0, 0, 0, 0.1)'
},
MCD: {
name: 'MCD',
'--dominant-color': '#E40031',
'--primary-color': '#0a84ff',
'--secondary-color': '#5e5ce6',
'--success-color': '#30d158',
'--warning-color': '#ff9f0a',
'--danger-color': '#ff453a',
'--bg-color': '#000000',
'--text-color': '#ffffff',
'--text-secondary': '#8e8e93',
'--border-color': '#38383a',
'--card-bg': '#1c1c1e',
'--mask-bg': 'rgba(255, 255, 255, 0.1)',
'--shadow-color': 'rgba(255, 255, 255, 0.1)'
},
LC: {
name: 'LC',
'--dominant-color': '#E40031',
'--primary-color': '#007aff',
'--secondary-color': '#5856d6',
'--success-color': '#4cd964',
'--warning-color': '#ff9500',
'--danger-color': '#ff3b30',
'--bg-color': '#E40031',
'--text-color': '#333333',
'--text-secondary': '#666666',
'--border-color': '#e0e0e0',
'--card-bg': '#ffffff',
'--mask-bg': 'rgba(0, 0, 0, 0.4)',
'--shadow-color': 'rgba(0, 0, 0, 0.1)'
},
custom: {
name: 'custom',
'--primary-color': '#ff6600',
'--secondary-color': '#ff9966',
'--success-color': '#67c23a',
'--warning-color': '#e6a23c',
'--danger-color': '#f56c6c',
'--bg-color': '#f9f9f9',
'--text-color': '#333333',
'--text-secondary': '#606266',
'--border-color': '#dcdfe6',
'--card-bg': '#ffffff',
'--mask-bg': 'rgba(0, 0, 0, 0.4)',
'--shadow-color': 'rgba(0, 0, 0, 0.1)'
}
} as any)
// 当前主题变量
const currentTheme = computed(() => themeConfig.value[themeName.value])
// 主题样式字符串(用于行内样式)
const themeStyleString = computed(() => {
const vars = currentTheme.value
let style = ''
for (const key in vars) {
if (key.startsWith('--')) {
style += `${key}: ${vars[key]}; `
}
}
return style
})
// 可用主题列表
const availableThemes = computed(() => Object.keys(themeConfig.value))
// 初始化主题
const initTheme = () => {
console.log('开始初始化主题...')
// 方法1:直接从本地存储读取(绕过Pinia持久化)
const saved = uni.getStorageSync('uni-theme')
console.log('从uni存储读取的主题:', saved)
// 方法2:从Pinia持久化读取
const piniaSaved = uni.getStorageSync('pinia-theme-store')
console.log('从Pinia存储读取的数据:', piniaSaved)
if (saved && themeConfig.value[saved]) {
console.log('使用uni存储的主题:', saved)
themeName.value = saved
} else if (piniaSaved) {
try {
const parsed = JSON.parse(piniaSaved)
if (parsed.themeName && themeConfig.value[parsed.themeName]) {
console.log('使用Pinia存储的主题:', parsed.themeName)
themeName.value = parsed.themeName
}
} catch (e) {
console.error('解析Pinia存储失败:', e)
}
} else {
console.log('使用默认主题: KFC')
themeName.value = 'KFC'
}
// 应用主题
applyTheme()
isThemeInitialized.value = true
// 监听系统主题变化
watchSystemTheme()
}
// 应用主题到页面
const applyTheme = () => {
console.log('应用主题:', themeName.value)
const theme = currentTheme.value
if (!theme) {
console.error('主题配置不存在:', themeName.value)
return
}
// 设置CSS变量(H5端)
if (typeof document !== 'undefined') {
const root = document.documentElement
for (const key in theme) {
if (key.startsWith('--')) {
root.style.setProperty(key, theme[key])
}
}
root.setAttribute('data-theme', theme.name)
console.log('CSS变量已设置')
}
// 发送主题变化事件
uni.$emit('theme:change', theme)
console.log('主题变化事件已发送:', theme.name)
// 保存到存储
uni.setStorageSync('uni-theme', themeName.value)
console.log('主题已保存到存储:', themeName.value)
}
// 监听系统主题
const watchSystemTheme = () => {
// H5端监听系统主题
if (typeof window !== 'undefined' && window.matchMedia) {
const darkModeMedia = window.matchMedia('(prefers-color-scheme: MCD)')
const handleThemeChange = (e : any) => {
if (uni.getStorageSync('uni-theme-follow-system') === true) {
setTheme(e.matches ? 'dark' : 'KFC')
}
}
darkModeMedia.addEventListener('change', handleThemeChange)
}
// App端监听系统主题
if (uni.getSystemSetting) {
const systemSetting = uni.getSystemSetting()
if (systemSetting) {
// App端逻辑
}
}
}
// 设置主题
const setTheme = (name : any) => {
if (!themeConfig.value[name]) {
console.warn(`主题 "${name}" 不存在`)
return false
}
themeName.value = name
applyTheme()
return true
}
// 切换主题
const toggleTheme = () => {
const themes = availableThemes.value
const currentIndex = themes.indexOf(themeName.value)
const nextIndex = (currentIndex + 1) % themes.length
setTheme(themes[nextIndex])
}
// 自定义主题变量
const updateCustomTheme = (key : any, value : any) => {
if (!key.startsWith('--')) {
key = `--${key}`
}
themeConfig.value.custom[key] = value
if (themeName.value === 'custom') {
applyTheme()
}
}
// 创建新主题
const createTheme = (name : any, config : any) => {
if (themeConfig.value[name]) {
console.warn(`主题 "${name}" 已存在`)
return false
}
themeConfig.value[name] = {
name,
...themeConfig.value.KFC, // 基于亮色主题
...config
}
return true
}
// 跟随系统主题
const followSystemTheme = (enable = true) => {
uni.setStorageSync('uni-theme-follow-system', enable)
if (enable) {
const isDark = window.matchMedia('(prefers-color-scheme: MCD)').matches
setTheme(isDark ? 'MCD' : 'KFC')
}
}
return {
// State
themeName,
themeConfig,
isThemeInitialized, // 导出初始化标记
// Getters
currentTheme,
themeStyleString,
availableThemes,
// Actions
initTheme,
setTheme,
toggleTheme,
updateCustomTheme,
createTheme,
followSystemTheme
}
}, {
persist: {
key: 'pinia-theme-store',
storage: {
getItem: (key:any) => {
const result = uni.getStorageSync(key)
console.log('Pinia持久化读取:', key, result)
return result
},
setItem: (key:any, value:any) => {
console.log('Pinia持久化保存:', key, value)
uni.setStorageSync(key, value)
},
removeItem: (key:any) => {
uni.removeStorageSync(key)
}
},
paths: ['themeName', 'themeConfig.custom']
}
})
引用示例
<template>
<!-- :style="themeStore.themeConfig[themeStore.themeName]"这个是在这个页面引用当前使用的主题样式 -->
<view :style="themeStore.themeConfig[themeStore.themeName]">
<!-- 当前为行内样式使用方法 -->
<view style="color: var(--dominant-color);"></view>
</view>
</template>
<script lang="ts" setup>
import {
onShow, onLoad
} from '@dcloudio/uni-app';
import { ref } from 'vue';
import {
useThemeStore
} from '@/store/theme';
const usersStore = useUsersStore();
const themeStore = useThemeStore()
</script>
<style lang="scss" scoped>
background: var(--dominant-color); //--dominant-color为你在主题管理定义的key
</style>
注:我本来想的是全局引用,但是不知道为什么一直引用失败,所以只能每个页面单独引入使用,如果各位有更好的方法可以用自己的方法。