app一键换肤功能的实现思路
- 定义全局需要切换的主题色(使用css变量 -- 开头)
- 使用pinia对全局主题色进行存储和转接
- 封装一键换肤组件和函数进行全局使用
第一步 [定义全局需要切换的主题色(使用css变量 -- 开头)]
我这里定义了两套主题色一套用于修改全局的背景和字体颜色,一套用于修改全局导航栏和tabBar
/* 亮色 */
.light {
--text-color: #333;
--bg-color: #fff;
}
/* 黑夜 */
.dark {
--text-color: #fff;
--bg-color: #272727;
}
/* teal */
.teal {
--text-color: #fff;
--bg-color: #008080;
}
/* violet */
.violet {
--text-color: #fff;
--bg-color: #9370DB;
}
/* almond */
.almond {
--text-color: #fff;
--bg-color: #ED9678;
}
/* chocolate */
.chocolate {
--text-color: #fff;
--bg-color: #CB8E85;
}
/* love */
.love {
--text-color: #fff;
--bg-color: #FF7875;
}
/* girl */
.girl {
--text-color: #fff;
--bg-color: #FFADD2;
}
/* blue */
.blue {
--text-color: #fff;
--bg-color: #ADC6FF;
}
export default {
light: {
baseColor: "#fff",
navigationBarStyle: {
frontColor: "#333",
backgroundColor: "#fff",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#fff",
borderStyle: "#151b29",
},
},
dark: {
baseColor: "#333",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#333",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#333",
borderStyle: "#f2f2f2",
},
},
teal: {
baseColor: "#008080",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#008080",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#008080",
borderStyle: "#008181",
},
},
violet: {
baseColor: "#9370DB",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#9370DB",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#9370DB",
borderStyle: "#008181",
},
},
almond: {
baseColor: "#ED9678",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#ED9678",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#ED9678",
borderStyle: "#008181",
},
},
chocolate: {
baseColor: "#CB8E85",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#CB8E85",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#CB8E85",
borderStyle: "#008181",
},
},
love: {
baseColor: "#FF7875",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#FF7875",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#FF7875",
borderStyle: "#008181",
},
},
girl: {
baseColor: "#FFADD2",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#FFADD2",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#FFADD2",
borderStyle: "#008181",
},
},
blue: {
baseColor: "#ADC6FF",
navigationBarStyle: {
frontColor: "#fff",
backgroundColor: "#ADC6FF",
animation: {
duration: 0,
timingFunc: "easeIn",
},
},
tabBarStyle: {
backgroundColor: "#ADC6FF",
borderStyle: "#008181",
},
},
};
第二步 [使用pinia对全局主题色进行存储和转接]
import { defineStore } from "pinia";
import systemTheme from '@/utils/systemTheme'
export const useTheme = defineStore({
id: "theme",
state: () => ({
themeType: uni.getStorageSync('theme') ?? '',
systemTheme: systemTheme
}),
getters: {
getThemeType() : any {
console.log(this.themeType);
return this.themeType;
},
},
actions: {
setTheme(e : string) {
// 存储到本地
uni.setStorageSync('theme', e);
this.themeType = e
plus.runtime.restart();
}
},
});
export const theme = () => {
const theme = useTheme()
return theme.themeType
}
第三步 [封装一键换肤组件]
<script lang="ts" setup>
import { theme, useTheme as themetype } from "@/store/module/theme";
import systemTheme from "@/utils/systemTheme";
import { onMounted, ref } from "vue";
interface ThemeItem {
k : string;
name : string;
color : string;
switchChecked : boolean
}
const themeList = ref<ThemeItem[]>([]);
const systemMsg = ref(false)
const event = ref()
const handleSwitch = (i) => {
themeList.value.forEach(item => {
item.switchChecked = item.k === i.k ? true : false
})
systemMsg.value = true
event.value = i.k
}
const handleConfirm = (e) => {
useTheme.setTheme(e)
systemMsg.value = false
}
const handleCancel = () => {
themeList.value.forEach(item => {
item.switchChecked = uni.getStorageSync('theme') == item.k ? true : false
})
systemMsg.value = false
}
onMounted(() => {
const type = {
light: '精灵白',
dark: '恶魔黑',
teal: '孔雀绿',
violet: '紫罗兰',
almond: '杏仁饼',
chocolate: '巧克力',
love: '薄暮',
girl: '少女',
blue: '拂晓蓝'
}
for (const k in systemTheme) {
themeList.value.push({
k,
name: type[k],
color: systemTheme[k]["baseColor"],
switchChecked: uni.getStorageSync('theme') == k ? true : false
});
}
});
</script>
<template>
<view :class="theme()" class="w-full ">
<view v-for="i in themeList" :key="i.name"
class="w-full h-auto flex justify-between items-center border-b border-[#f2f2f2] px-[20rpx] py-[20rpx]">
<view class="w-[40rpx] h-[40rpx] rounded-full"
:style="{backgroundColor: `${i.color}`,border:`${i.color == '#fff' ? '1rpx solid #d9d9d9':'1rpx solid #fff'}`}">
</view>
<view class="text-[14px] text-[#222]">
{{i.name}}
</view>
<nut-switch v-model="i.switchChecked" :active-color="i.color=='#fff'?'pink':i.color"
@click="handleSwitch(i)" />
</view>
<u-modal :show="systemMsg" :showCancelButton="true" @cancel="handleCancel" @confirm="handleConfirm(event)"
confirmText='重启' cancelText="取消" title="系统提示" content='系统主题应用成功,是否重启生效'></u-modal>
</view>
</template>
第五步 [封装全局修改导航条和tabBar主题的函数]
import systemTheme from '@/utils/systemTheme'
export default function (time : number) {
const system = uni.getStorageSync('theme')
setTimeout(() => {
uni.setNavigationBarColor(systemTheme[system].navigationBarStyle);
//设置tabbar主题
uni.setTabBarStyle(systemTheme[system].tabBarStyle)
}, time)
}
应用
在App.ts使用
<script setup lang="ts">
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
import modifyNavigationBarStyle from '@/utils/modifyNavigationBarStyle'
import { onMounted } from "vue";
onLaunch(() => {
const naviArr = [
'navigateTo',
'redirectTo',
'reLaunch',
'switchTab',
'navigateBack',
]
for (let i of naviArr) {
uni.addInterceptor(i, {
//监听跳转
success(e) {
// 修改导航条
void modifyNavigationBarStyle(0)
},
})
}
});
onShow(() => {
});
onHide(() => { });
onMounted(() => {
// 修改导航条
void modifyNavigationBarStyle(200)
})
</script>
<style lang="scss">
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
@import "@/uni_modules/uview-plus/index.scss";
@import "nutui-uniapp/styles/index";
/* 适配tailwindcss */
@import url("@/style/tailwindcss.css");
</style>