前面我已經給大家介紹了兩種主題切換的方式,每種方式各有自己的優勢與缺點,例如“scss變量+vuex”方式相容好但不好維護與擴充,“scss變量+require”方式好維護但相容不好,還不清楚的可點下面連結直達了解一下
uniapp主題切換功能的第一種實作方式(scss變量+vuex)
uniapp主題切換功能的第二種實作方式(scss變量+require)
了解了這些才能更好的了解我接下來給大家總結的。
最後做的這個能相容所有平台的主題切換效果,大家可以微信掃碼一睹為快,切換功能在”個人中心“那裡(模仿的b站),目前分白天與夜間模式
接下來就給大家介紹一下如何做一個相容好,又好維護的主題切換功能
解決思路
uniapp應用在做開發的時候,拆分頁面其實就分兩大部分,主體部分+導航欄與tabbar
為什麼要這麼分,因為主體部分的樣式通常是普通css代碼控制的,而導航欄+tabBar(例如原生的情況)須要通過api去修改。而css與js目前還不能完全互通。
是以要做全平台相容同樣須要維護主體部分的樣式(純css)與導航欄+tabBar部分的樣式(js),明白了原理,接下來就上代碼
第一部分:全局“主體部分”主題樣式
這樣其實就是之前講過的,上代碼
定義common/css/_theme.scss
$themes: (
// 白天模式
light:(
page: (
background-color: #fff,
color: (
color: #333,
),
block: (
background-color: #333,
color: (
color: #fff,
),
),
),
user-page: (
background-color: #f2f2f2,
color: (
color: #666,
),
block: (
background-color: #999,
color: (
color: #000,
),
),
),
),
// 夜間模式
dark:(
page: (
background-color: #333,
color: (
color: #fff,
),
block: (
background-color: #fff,
color: (
color: #000,
),
),
),
user-page: (
background-color: #1a1a1a,
color: (
color: #fff,
),
block: (
background-color: #FFFFFF,
color: (
color: #000,
),
),
),
)
);
生成主題樣式
@mixin map-to-class($map, $divider: "-", $select: ".theme", $isRoot: false, $root-select: ".theme") {
$select: if($select== "" and &, &, $select);
@each $k, $v in $map {
$currSelect: if($isRoot, #{$root-select}#{$divider}#{$k}, #{$select}#{$divider}#{$k});
#{$currSelect} {
@if type-of($v) ==map {
@include map-to-class($v, $divider, "", true) {
@content;
}
} @else {
@at-root #{$select} {
#{$k}: $v !important;
}
}
}
}
}
@each $key, $mode in $themes {
@if $key== "light" {
@include map-to-class($mode);
}
}
// 或
@each $key, $mode in $themes {
@if $key== "dark" {
@include map-to-class($mode);
}
}
其實可以循環一次性輸出,這個交給你們了。。。
頁面使用
<template>
<view class="tpf-page theme-page">
<text class="theme-color">訂單</text>
<view class="theme-block block flex flex-align-center flex-pack-center">
<text class="theme-color">闆塊裡面的文本</text>
</view>
<view class="flex flex-align-center flex-pack-justify change-theme">
<text class="button" @tap="changeTheme('light')">白天模式</text>
<text class="button dark" @tap="changeTheme('dark')">夜間模式</text>
</view>
</view>
</template>
這裡主要通過加theme字首(你自己可以改成想要的)的類theme-page、theme-color、theme-block等等等的方式給内容塊加背景,給字型加顔色等
這樣頁面是不是就很好維護,不同顔色的頁面,你隻須要在_theme.scss主題裡面進行添加或修改後,在頁面添加回應的theme-xxx類即可。
這樣就處理了主體部分的樣式主題切換問題。
第二部分:全部“導航欄+tabBar”主題樣式
因為這部分涉及到原生操作,須要用到api,是以必須是js來維護主題樣式
定義theme.js
// 定義導航欄 與 tabbar 主題色
const themes = {
light:{
navBar:{
backgroundColor:'#FFF',
frontColor:"#000000"
},
tabBar:{
backgroundColor:'#FFF',
color:'#333',
selectedColor:'#0BB640',
borderStyle:'white'
}
},
dark:{
navBar:{
backgroundColor:'#333',
frontColor:"#ffffff"
},
tabBar:{
backgroundColor:'#333',
color:'#fff',
selectedColor:'#0BB640',
borderStyle:'black'
}
}
}
export default themes;
第一種使用方式vue.prototype的全局挂載(不推薦)
不推薦的原因:::有相容問題!!!
mian.js
//引入主題
import themes from '@/common/theme/theme.js';
....
//全局挂載
Vue.prototype.$themes = themes;
第二種使用方式:Vuex / globalData
為什麼使用這兩種,因為他們是目前官方相容所有平台的,這裡我隻介紹Vuex的方式
建立store.js
import Vue from 'vue'
import Vuex from 'vuex'
// 引入主題
import themes from '@/common/theme/theme.js';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
theme:themes[uni.getStorageSync('theme') || 'light']
},
getters: {
},
mutations: {
updateTheme(state,mode = 'light'){
state.theme = themes[mode];
}
}
})
export default store
頁面使用
建立好store之後,就可以在頁面裡面動态設定導航欄與tabBar了,具體大家自己去根據喜好封裝。
onReady(){
//Vuex的方式
// 設定導覽列
uni.setNavigationBarColor(this.$store.state.theme.navBar);
// 設定tabbar
uni.setTabBarStyle(this.$store.state.theme.tabBar);
},
如何實作切換
更新就是更改store的狀态,因為他是全局的,所有頁面都能應用到
this.$store.commit("updateTheme",mode);
// 設定導覽列
uni.setNavigationBarColor(this.$store.state.theme.navBar);
// 設定tabbar
uni.setTabBarStyle(this.$store.state.theme.tabBar);
最後總結
要想實作全端相容,肯定所有的代碼都要考慮到相容所有平台,因為做的時候要就考慮到。
主題切換對于應用來說是一個大工程,原理給大家說了,實作部署還須要大家好好的思考,其中擴充性,可維護性等都必須事先考慮的,不然項目肯定做不大。
想看我做的最終成品怎麼樣,可以掃碼看看
有什麼做得不好的,或沒有考慮到位的,歡迎大家留言讨論交流,共同學習進步。