uni-app 動態修改主題色

虛乄發表於2022-12-14

老是碰到初版製作完成沒多久,就整一出說什麼要更改整個專案的色彩體系。真的是寶寶心裡苦啊!

起初都是透過uni專案自帶的uni.scss中定義,在替換頁面上對應的css。以便於達到一次性修改整體佈局的樣式。

一.uni.scss 使用方式

在該檔案裡定義: $名字 :顏色值;

使用時需要在 style 節點上加上 lang=“scss”

<style lang="scss" scoped>
    .bg {
        height: 120px;
        width: 100%;
        background-color: $uni-color-primary;
    }
</style>

該方法使用,適合單一顏色修改,一次修改全域性統一。

二.暗黑主題

暗黑模式(Dark Mode),也被稱為夜間模式或深色模式,是一種高對比度,或者反色模式的顯示模式。是一種有利於在黑暗環境下觀看手機的高對比度的模式。uni-app的暗黑模式,是幫助開發者完成自己應用的暗黑模式的一批配置和API。開發者可以參考本文實現自己應用的暗黑模式。

注:HBuilder X 3.6.9+ 支援 目前只支援深色和淺色

具體介紹看官網地址:https://uniapp.dcloud.net.cn/tutorial/darkmode.html

三.自定義主題配置

可自行定義多種主題配色,透過js動態修改導航欄等色彩。缺點在於,頁面載入緩慢時前期會顯示出原有的色彩。整體上不影響使用。

注:在APP 微信小程式 H5 都行

1.在根目錄下新建 theme 資料夾

css-theme.scss 主題適配主要css

css-variate.scss 統一顏色值配置

cue-theme.js vue 混入js

system-theme.js 自定義的相關配置

css-theme

主要為使用sass切換主題,百度一下大部分都是按照以下配置,這裡不過多介紹

注:uni中使用時 建議這個scss 在 uni.scss 中 引入該scss

uni-app 動態修改主題色
/*
* @author: Jay
* @description: 透過監聽 css 變數切換主題色
* @createTime: 2022-12-13 11:29:00
* @introduce: 需要在 uni.scss 中 引入該scss
*/

//統一配置色彩
@import "./css-variate.scss";

/*---------------------方法一 使用css 控制變數  ---------------------------*/
/*
    使用方法
    .css-theme {
        width: 100%;
        @include text-color();
        @include base-background();
        @include border-color();
        @include shadow-color();
    }
*/

/* 白天主題 顏色集合 */
$day-theme:(
    bg-color:$day-bg,
    text-color:$day-text,
    border-color: $day-border,
    shadow-color:$day-shadow
);

/* 夜間主題 顏色集合 */
$night-theme:(
    bg-color:$night-bg,
    text-color:$night-text,
    border-color: $night-border,
    shadow-color: $night-shadow
);

/* 玉紅主題 顏色集合 */
$jade-theme:(
    bg-color:$jade-bg,
    text-color:$jade-text,
    border-color: $jade-border,
    shadow-color: $jade-shadow
);

//定義主題物件
$themes: (
  day-theme: $day-theme,
  night-theme: $night-theme,
  jade-theme: $jade-theme
);

// 生成主題背景色樣式
@mixin base-background(){
    @each $themename , $theme in $themes {
        &.#{$themename} {
            background-color: map-get($map: $theme, $key: bg-color);
        }
    }
}

// 生成主題字型色樣式
@mixin text-color(){
    @each $themename , $theme in $themes {
        &.#{$themename} {
            color: map-get($map: $theme, $key: text-color) !important;
        }
    }
}

// 生成主題邊框色樣式
@mixin border-color($opa: 1.0){
    @each $themename , $theme in $themes {
        &.#{$themename} {
            border-color: rgba(map-get($map: $theme, $key: border-color), $opa) !important;
        }
    }
}

// 生成主題陰影
@mixin shadow-color(){
    @each $themename , $theme in $themes {
        &.#{$themename} {
            box-shadow: 0 16rpx 32rpx rgba(map-get($map: $theme, $key: shadow-color), 0.4);
        }
    }
}

/*---------------------方法二 使用css 屬性選擇器  ---------------------------*/
/*
    使用方法
        <view class="padding-sm" :data-theme="cueTheme">
            暗黑模式-官方自帶:(只支援 白天黑夜)
        </view>
*/

/* 白天主題 */
[data-theme='day-theme'] {
    background-color: $day-bg;
    color: $day-text;
    border-color: $day-border !important;
    shadow-color: $day-shadow;
}

/* 夜間主題 */
[data-theme='night-theme'] {
    background-color: $night-bg;
    color: $night-text;
    border-color: $night-border !important;
    shadow-color: $night-shadow;
}

/* 玉紅主題 */
[data-theme='jade-theme'] {
    background-color: $jade-bg;
    color: $jade-text;
    border-color: $jade-border !important;
    shadow-color: $jade-shadow;
}
css-theme

uni.scss中引入

/* 主題相關顏色 */
@import './theme/css-theme.scss';

css-variate

主要為配置主題所需css 顏色值,方便統一修改。

uni-app 動態修改主題色
/*
    主題 統一配置色彩
*/

//頁面背景色
$page-bg:var(--page-bg,#FFFFFF);

// 白天主題
$day-bg: #FFFFFF;
$day-text: #333333;
$day-border: #c8c7cc;
$day-shadow: #c8c7cc;

// 夜間主題
$night-bg: #292929;
$night-text: #FFFFFF;
$night-border: #c8c7cc;
$night-shadow: #FFFFFF;

// 玉紅主題
$jade-bg: #c04851;
$jade-text: #FFFFFF;
$jade-border: #eea2a4;
$jade-shadow: #f1939c;

/*
    需要在js 中使用的css 匯出
        APP 無法使用
        h5 微信小程式有值
*/

:export {
    dayBg: $day-bg;
    nightBg: $night-bg;
    jadeBg: $jade-bg;
}
css-variate

cue-theme

主要使用 混入 (mixin) ,方便與在頁面中複用相同的功能。

該方法主要呼叫vuex的資料 和 system-theme 中的方法

注:需要在main.js 匯入該js

uni-app 動態修改主題色
/*
 * @author: Jay
 * @description: 監聽主題變化
 * @createTime: 2022-12-12 15:22:19
 */
import system from '../theme/system-theme'
import {
    mapMutations,
    mapGetters
} from 'vuex'
export default {
    install(Vue) {
        Vue.mixin({
            onShow() {
                //修改導航欄 底部 tab
                system.setSystemTheme(this.cueTheme)
                //獲取快取 背景色
                let bgColor = uni.getStorageSync('pageColor') || '';
                if (bgColor) {
                    this.getSystemBg(bgColor)
                }
                //獲取快取 主題名字
                let themeType = uni.getStorageSync('themeType') || '';
                if (themeType) {
                    this.cueGetTheme(themeType)
                }
                // 監聽主題狀態變化
                uni.onThemeChange((res) => {
                    // console.log("監聽主題狀態變化", res.theme);
                    //黑夜
                    if (res.theme == 'dark') {
                        this.cueGetTheme('night-theme')
                    }
                    //白天
                    if (res.theme == 'light') {
                        // 有多個主題時 判斷 快取是否為白色主題
                        let type = uni.getStorageSync('themeType');
                        if (type != 'day-theme') {
                            this.cueGetTheme(type)
                        } else {
                            this.cueGetTheme('day-theme')
                        }
                    }
                });
            },
            computed: {
                // 獲取vuex 主題引數
                ...mapGetters({
                    cueTheme: 'theme/theme',
                    pageBg: 'theme/pageColor',
                }),
            },
            methods: {
                // 修改主題
                ...mapMutations({
                    cueGetTheme: 'theme/GET_THEME',
                    themeCache: 'theme/SET_THEME_CACHE',
                    pageColorCache: 'theme/SET_PAGE_COLOR'
                }),
                // 設定 全域性背景色
                getSystemBg() {
                    //從 主題列表 獲取 頁面顏色
                    let bgColor = system.systemThemeBg(this.cueTheme)
                    // console.log(bgColor);
                    //快取 已設定 背景色
                    this.pageColorCache(bgColor)
                }
            }
        })
    }
}
cue-theme

main.js 匯入

//監聽主題變化
import theme from './theme/cue-theme.js'
Vue.use(theme)

system-theme

主要用來放置一些需要重複使用的js。可根據需求自行新增

注: themeList 為系統主題列表引數相關配置,用於全域性設定系統導航欄,底部tab顏色值的存放。

注:其中匯入 css-variate.scss 在app 沒有相關資料返回,h5,微信小程式則有資料返回。其他平臺自行測試。

uni-app 動態修改主題色
/*
 * @author: Jay
 * @description: 主題相關配置
 * @createTime: 2022-12-12 17:45:09
 */

/* 
    variables APP 拿不到值
    h5 微信小程式有值返回
*/
import variables from './css-variate.scss'
export default {
    /* 
        系統主題列表
    */
    themeList() {
        return [{
            title: "白天",
            name: "day-theme",
            navBg: variables.dayBg,
            navBgApp: "#FFFFFF",
            tabBg: "",
            tabSeleText: "",
            tabText: "",
        }, {
            title: "黑夜",
            name: "night-theme",
            navBg: variables.nightBg,
            navBgApp: "#292929",
            tabBg: "",
            tabSeleText: "",
            tabText: "",
        }, {
            title: "玉紅",
            name: "jade-theme",
            navBg: variables.jadeBg,
            navBgApp: "#c04851",
            tabBg: "",
            tabSeleText: "",
            tabText: "",
        }]
    },
    //根據主題 返回背景色
    systemThemeBg(name) {
        let color = ''
        this.themeList().map((item, index) => {
            if (item.name === name) {
                color = item.navBgApp
            }
        })
        return color
    },
    //根據主題 修改系統 導航欄 底部 tab
    setSystemTheme(name) {
        this.themeList().map((item, index) => {
            if (item.name === name) {
                // 設定頁面導航條顏色
                this.setNavigationColor(item.name, item.navBgApp)
                // 設定 tabBar 樣式
                this.setTabBarColor(item.tabBg, item.tabSeleText, item.tabText)
            }
        })
    },
    /* 
        設定頁面導航條顏色 
        name 主題名字  該顏色值只支援2種 故判斷對於白天 為 #000 其他均為 #FFF
        bgClor 背景色  可以隨意修改
    */
    setNavigationColor(name, bgClor) {
        let navigationBar = {
            // 前景顏色值 僅支援 #ffffff 和 #000000
            frontColor: name == 'day-theme' ? "#000000" : "#ffffff",
            // 背景顏色值
            backgroundColor: bgClor || "#FFFFFF",
            // fail(err) {
            //     console.error(err)
            // }
        }
        uni.setNavigationBarColor(navigationBar)
    },

    /* 
        動態 設定 tabBar 樣式
    */
    setTabBarColor(bgColor, seleColor, color) {
        let tabBar = {
            // 背景色
            backgroundColor: bgColor || '#ffffff',
            // 文字選中時的顏色
            selectedColor: seleColor || '#3cc51f',
            // 文字預設顏色
            color: color || '#7A7E83',
        }
        uni.setTabBarStyle(tabBar)
    }
}
system-theme

2.vuex 配置

使用vuex模組化開發(module)用於區分主題相關設定 與其他需求。

theme.js 模組

注:namespaced: true 主要為 cue-theme 用於模組化呼叫。缺少這個,在呼叫cue-theme中的方法時,拿不到所需引數

uni-app 動態修改主題色
//主題相關配置
import system from '../../theme/system-theme'

const theme = {
    namespaced: true, 
    state: {
        theme: "day-theme",
        //主題列表
        theme: system.themeList(),
        //頁面背景色
        pageColor: "",
    },
    mutations: {
        //設定主題色
        GET_THEME(state, provider) {
            state.theme = provider
            //修改導航欄 底部 tab
            system.setSystemTheme(state.theme)
        },
        //設定主題快取
        SET_THEME_CACHE(state, provider) {
            uni.setStorage({
                key: 'themeType',
                data: provider
            });
        },
        //設定主題快取
        SET_PAGE_COLOR(state, provider) {
            state.pageColor = provider
            //快取
            uni.setStorage({
                key: 'pageColor',
                data: provider
            });
        },
    },
    getters: {
        theme: state => state.theme,
        pageColor: state => state.pageColor
    },
    actions: {

    }
}

export default theme
theme.js

index.js 全域性匯出

uni-app 動態修改主題色
import Vue from "vue"
import Vuex from "vuex"
//登入
import logIn from "./modules/login.js"
//主題切換
import theme from "./modules/theme.js"

Vue.use(Vuex)
const store = new Vuex.Store({
    modules: {
        theme,
        logIn
    }
})

export default store
index.js

main.js中匯入

//引入store
import store from 'store/index.js'
Vue.prototype.$store = store

3.頁面中使用

class="conter" :style="{'--page-bg':pageBg}" 為該頁面單獨設定背景色 ,需要配合 page 設定頁面高度使用

:data-theme="cueTheme" 給view設定data-theme屬性,根據名字匹配對應顏色

:class="[cueTheme]" 設定對應的名字, css 中使用 @include text-color();

案例地址: https://gitee.com/jielov/uni-app-tabbar

uni-app 動態修改主題色
<!--
* @author: Jay
* @description: 動態修改主題色
* @createTime: 2022-12-12 14:55:31
 -->
<template>
    <view class="conter" :style="{'--page-bg':pageBg}">
        <view class="padding margin-bottom-xl css-theme" :class="[cueTheme]">
            <view class="text-lg text-center text-bold">
                暗黑模式
            </view>
            <view class="margin-top-sm" @click="openDoc">
                uni-app的暗黑模式。<text class="text-blue">點選檢視官方文件</text>
            </view>
        </view>

        <view class="css-theme padding" :class="[cueTheme]">
            <view class="text-center text-bold text-lg">
                透過判斷css 名字修改主題!!!
            </view>
            <view class="margin-tb-sm text-lg text-center">
                當前主題:{{cueTheme}}
            </view>
            <view class="margin-tb-sm text-lg text-center">
                當前頁面背景色:{{pageBg}}
            </view>
            <view class="flex align-center justify-around">
                <button class="cu-btn round" @click="cssEditThemeBut('day-theme')">白天</button>
                <button class="cu-btn round" @click="cssEditThemeBut('night-theme')">黑夜</button>
                <button class="cu-btn round" @click="cssEditThemeBut('jade-theme')">玉紅</button>
            </view>
        </view>

        <view class="padding margin-top-xl" :data-theme="cueTheme">
            <view class="text-center text-bold text-lg">
                透過 data-theme 判斷 名字修改主題!!!
            </view>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                url: 'https://uniapp.dcloud.net.cn/tutorial/darkmode.html#open-darkmode'
            };
        },
        onLoad() {
            console.log("當前主題:", this.cueTheme);
        },
        onShow() {},
        methods: {
            cssEditThemeBut(e) {
                //修改主題
                this.cueGetTheme(e)
                //設定主題快取
                this.themeCache(e)
                //設定 全域性背景色
                this.getSystemBg()
                // js自改變數值  h5 可用
                // document.getElementsByTagName('body')[0].style.setProperty('--page-bg', 'red');
            },
            openDoc() {
                // #ifdef APP
                plus.runtime.openWeb(this.url);
                // #endif
                // #ifdef H5
                let a = document.createElement('a');
                a.href = this.url;
                a.target = '__blank';
                a.click();
                a = null;
                // #endif
            }
        }
    }
</script>
<style>
    /* 全域性背景色 */
    page {
        height: 100%;
    }
</style>
<style lang="scss" scoped>
    // 全域性背景色
    .conter {
        height: 100%;
        background-color: $page-bg;
    }

    .css-theme {
        // border: 2px solid;
        @include text-color();
        @include base-background();
        @include border-color();
        @include shadow-color();
    }
</style>
頁面程式碼

四.黑夜 白天主題展示

 

相關文章