uniapp主題切換功能的第二種實現方式(scss變數+require)

2023-06-07 15:00:41

在上一篇 「uniapp主題切換功能的第一種實現方式(scss變數+vuex)」 中介紹了第一種如何切換主題,但我們總結出一些不好的地方,例如擴充套件性不強,維護起來也困難等等,那麼接下我再給大家介紹另外一種切換主題的方法「scss變數+require」的方式

在介紹如何使用前,先看下最後的效果,以便大家能更好的理解,下面是效果圖:

除了圖上的這個頁面切換了外,整體專案都有主題色的切換,具體效果可掃碼自行檢視。

接下來詳細介紹下第二種實現方式

實現原理

定義兩套主題色(多套再自己加)theme-dark.scss、theme-light.scss,每套主題色維護著自己的顏色,通過require動態引入scss的形式引入當前主題,從而達到切換主題的目的

第一步:建立不同主題色

建立白天與夜晚模式

建立白天模式

common/theme/theme-dark.scss

/* 切換主題主要切換的是  整體背景色、區塊背景色、文字顏色等 */

// 頁面主題
.theme-page{
	background-color: #333 !important;
	// 文字顏色
	.theme-color{
		color: #FFF !important;
	}
	// 區塊主題色
	.theme-block{
		background-color: #FFFFFF !important;
		.theme-color{
			color: #000 !important;
		}
	}
}

// 如果想單獨給個人中心設定一個主題色
.theme-user-page{
	background-color: #1a1a1a !important;
	// 文字顏色
	.theme-color{
		color: #FFF !important;
	}
	// 區塊主題色
	.theme-block{
		background-color: #FFFFFF !important;
		.theme-color{
			color: #000 !important;
		}
	}
}

建立夜間模式

common/theme/theme-light.scss

/* 切換主題主要切換的是  整體背景色、區塊背景色、文字顏色等 */

// 頁面主題
.theme-page{
	background-color: #FFF !important;
	// 文字顏色
	.theme-color{
		color: #333 !important;
	}
	// 區塊主題色
	.theme-block{
		background-color: #999 !important;
		.theme-color{
			color: #333 !important;
		}
	}
}

// 如果想單獨給個人中心設定一個主題色
.theme-user-page{
	background-color: #F2F2F2;
	// 文字顏色
	.theme-color{
		color: #666 !important;
	}
	// 區塊主題色
	.theme-block{
		background-color: #999 !important;
		.theme-color{
			color: #000 !important;
		}
	}
}

東西多了的情況,例如有5套主題色,分開不是很好維護,所以

可以考慮把顏色值獨立出去

改進:獨立主題色

定義_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);
    }
}

大家可以用sass編輯器看一下最終的樣式是什麼樣的

第三步:App.vue動態引入

在App.vue裡面通過require動態引入主題,當前每次切換主題的時候要把當前主題資料進行儲存。

onLaunch: function() {
    let theme = uni.getStorageSync('theme') || 'light';
    // import `@/common/theme/theme-${mode}.scss`;  //記住不能import哦
    require(`@/common/theme/theme-${theme}.scss`);
},
// ......

這樣就實現了動態引入

以後只須要維護_theme.scss即可

最後測試

測試程式碼:

<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>

<script>
export default{
	data(){
		return {
			
		}
	},
	methods:{
		changeTheme(mode){
			uni.setStorageSync('theme',mode);
			setTimeout(()=>{
				location.reload();
			},200);
		}
	},
	onReady() {
		let theme = uni.getStorageSync('theme') || 'dark';
		if(theme == 'dark'){
			// 動態設定導覽列顏色
			uni.setNavigationBarColor({
				frontColor:'#ffffff',
				backgroundColor:'#333333'
			});
			
			// 動態設定tabbar樣式
			uni.setTabBarStyle({
				backgroundColor:'#333333',
				color: '#FFF',
				selectedColor: '#0BB640',
				borderStyle: 'white'
			});
		}else{
			// 動態設定導覽列顏色
			uni.setNavigationBarColor({
				frontColor:'#000000',
				backgroundColor:'#FFFFFF'
			});
			
			// 動態設定tabbar樣式
			uni.setTabBarStyle({
				backgroundColor:'#FFFFFF',
				color: '#333',
				selectedColor: '#0BB640',
				borderStyle: 'black'
			});
		}
	}
}
</script>

<style lang="scss" scoped>
.block{
	width: 710rpx;
	height: 300rpx;
	margin: 20rpx 0;
}
.change-theme{
	width: 400rpx;
}
.button{
	background-color:#FFF;
	color: #000;
	padding: 20rpx;
}
.dark{
		background-color: #000;
		color: #FFF;
}
</style>

在這裡導航欄與tabbar都是通過手動設定的,因為必須是js操作,所以樣式不能去讀css,為了方便,我們也可以定義一個theme.js專門來維護導航欄與tabar樣式

補充theme.js

theme.js定義主題案例程式碼:

const themes = {
	light:{
		navBar:{
			bgColor:'#000',
			color:'#FFF'
		},
		tabBar:{
			bgColor:'#000',
			color:'#FFF',
			borderStyle:'black'
		}	
	},
	dark:{
		navBar:{
			bgColor:'#FFF',
			color:'#000'
		},
		tabBar:{
			bgColor:'#f2f2f2',
			color:'#333',
			borderStyle:'white'
		}
	}
}

let mode = 'dark'

export default themes[mode];

頁面就可以通過引入這個js,通過當前主題引入相關的設定即可。這樣方便統一維護與管理 。

最後總結

scss變數+require的方式明顯比第一種要好,減少了頁面與主題的耦合度,維護起來也方便

但出於一些效能上的問題(官方回答),在某些平臺或版本已經取消了require動態引入樣式的功能,因此這個是有相容問題的。

這就是我給大家介紹的第二種unippa主題切換的方式,有問題歡迎大家留言交流。https://www.cnblogs.com/top8/p/17460706.html