uniapp主題切換功能的方式終結篇(全平臺相容)

2023-06-08 12:01:11

前面我已經給大家介紹了兩種主題切換的方式,每種方式各有自己的優勢與缺點,例如「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-pagetheme-colortheme-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);

最後總結

要想實現全端相容,肯定所有的程式碼都要考慮到相容所有平臺,因為做的時候要就考慮到。

主題切換對於應用來說是一個大工程,原理給大家說了,實現部署還須要大家好好的思考,其中擴充套件性,可維護性等都必須事先考慮的,不然專案肯定做不大。

想看我做的最終成品怎麼樣,可以掃碼看看

有什麼做得不好的,或沒有考慮到位的,歡迎大家留言討論交流,共同學習進步。