uni-app框架开发App更换主题皮肤

1,046 阅读3分钟

一、解决思路

换肤换的是背景色、字体颜色、边框色。其中,白天版light是默认。然后,在uni.scss当中定义全局的颜色变量,再义一个class类,在切换到dark的时候,显示这个class类,用于覆盖light下的原有颜色,用于显示黑夜版的皮肤。切换到light的时候,这个类消失,展示出白天版的皮肤。

解决方案

1、在页面放置一个切换皮肤的按钮:

image.png

切换函数如下:

handleChangeSkin() {
  const isDark = this.isDark;
  const theme = isDark ? 'dark' : 'light';
  console.log(theme);
  this.setCurThemeType(theme);
  //切换的主题缓存起来
  uni.setStorageSync('theme', theme);
  //动态的改变定义在vuex当中的变量,达到动态换肤的效果
  this.$store.dispatch('handleActionTheme', theme);
  getApp().handleSetTabBar();
  //下面的代码用于动态的改变APP底部导航的颜色。
  if (isDark) {
    uni.setTabBarStyle({
      color: '#9299A7',
      selectedColor: '#3C79FF',
      backgroundColor: '#2B3757'
    });
  } else {
    uni.setTabBarStyle({
      color: '#9299A7',
      selectedColor: '#3C79FF',
      backgroundColor: '#fff'
    });
  }
},

其中 uni.setStorageSync('theme', theme);是将切换的主题缓存起来,下次进入的时候在缓存当中直接取值。

this.$store.dispatch('handleActionTheme', theme);用于动态的改变定义在vuex当中的变量,达到动态换肤的效果。

2、在uni.scss当中定义变量:

// light background
$light-bg-main: #f5f5f5;
$light-bg-gross: #fff;
$light-bg-menu: #f5f5f5;
// dark background
$dark-bg-main: #19223a;
$dark-bg-gross: #1d2742;
$dark-bg-menu: #2b3757;
// light font
$light-font-title: #666;
$light-font-gross: #666;
// dark font
$dark-font-title: rgba(255, 255, 255, 0.7);
$dark-font-gross: rgba(255, 255, 255, 0.7);
// light border
$light-border-divide: #dfdfdf;
// dark border
$dark-border-divide: #364364;

3、在sass文件当中定义两种不同的类,用于切换不同的皮肤下,所展示出来的颜色。

.main {
  background-color: $light-bg-main;
  &-dark {
    background-color: $dark-bg-main;
  }
}
.menu {
  background-color: $light-bg-menu;
  &-dark {
    background-color: $dark-bg-menu;
  }
}
.gross {
  background-color: $light-bg-gross;
  color: $light-font-gross;
  &-dark {
    background-color: $dark-bg-gross;
    color: $dark-font-gross;
  }
}
.divide {
  border-bottom-style: solid;
  border-bottom-width: 1px;
  font-size: 12px;
  border-color: $light-border-divide;
  &-dark {
    border-color: $dark-border-divide;
  }
}
.titleFont {
  color: #333;
  &-dark {
    color: rgba(255, 255, 255, 0.9);
  }
}

4、在vuex的index.js当中定义切换的变量、切换的函数:

 
export default new Vuex.Store({
  state: {
    curThemeType: 'light',
  },
  mutations: {
    setCurThemeType(state, data) {
      state.curThemeType = data;
    }
  },
  actions: {
    handleActionAgree({ commit }, boo) {
      commit('handleAgree', boo);
    },
  },
  getters: {
    themeType(state) {
      return state.curThemeType;
    }
  },
  modules: {}
});

5、使用 mixin混合机制,让主题变量themeType,成为全局变量,是的每个组件都能获得拥有 mixin中的方法和属性:

import { mapGetters, mapMutations } from 'vuex';
export default {
  install(Vue) {
    Vue.mixin({
      mixins: [MescrollMixin, MescrollMoreItemMixin], // 使用mixin
      data() {
        return {
        };
      },
      methods: {
        ...mapMutations(['setCurThemeType']),
      },
      computed: {
        ...mapGetters(['themeType'])
      },
     
    });
  }
};

6、然后再main.js里引入  minxin.js:

import Vue from 'vue';
import App from './App';
import moment from 'moment';
import VueI18n from 'vue-i18n';
import store from './store';
import myMixin from './common/mixins.js';
import uView from 'uview-ui';
const en = require('@/lang/en-us.json');
const zh = require('@/lang/zh-cn.json');
const tw = require('@/lang/zh-tw.json');
const ja = require('@/lang/ja-jp.json');
const mergeZH = Object.assign({}, zh);
const mergeEN = Object.assign({}, en);
const mergeTW = Object.assign({}, tw);
const mergeJA = Object.assign({}, ja);
// import VConsole from 'vconsole';
//let vConsole = new VConsole();
Vue.use(VueI18n);
Vue.use(myMixin);
Vue.use(uView);
const i18n = new VueI18n({
  locale: store.state.lang,
  messages: {
    'en-US': {
      lang: mergeEN
    },
    'zh-CN': {
      lang: mergeZH
    },
    'zh-TW': {
      lang: mergeTW
    },
    'ja-JP': {
      lang: mergeJA
    }
  }
});
App.mpType = 'app';
Vue.prototype._i18n = i18n;
Vue.prototype.moment = moment;
const app = new Vue({
  i18n,
  store,
  ...App
});
app.$mount();
export default app;

7、最后在需要切换主题的界面,例如index.vue里配置如下:

<template>
  <view
    class="gross"
    :class="themeType === 'dark' ? 'gross-dark' : ''"
    style="min-height: 100%"
  >
  </view>
</template

最后,通过点击按钮就可以进行主题的切换。

8、配置默认显示主题:\

在APP.vue里 配置如下:
onLaunch()   这个方法是当App加载完毕后就执行;
如果缓存有 主题,就用缓存中的主题, 没有则用 light主题

import { mapMutations } from 'vuex';
 onLaunch() {
    this.$store.dispatch('handleGetWordKey');
    this.handleInit();
    this.handleSetTabBar();
    const list = this.auth.getWallets();
    getApp().globalData.account_list = list ? list : [];
  },
 methods: {
    ...mapMutations(['setCurThemeType']),
    handleSetTabBar() {
      const theme = uni.getStorageSync('theme');
      this.setCurThemeType(theme);
      if (theme === 'dark') {
        uni.setTabBarStyle({
          color: '#9299A7',
          selectedColor: '#3C79FF',
          backgroundColor: '#2B3757'
        });
      } else {
        uni.setTabBarStyle({
          color: '#9299A7',
          selectedColor: '#3C79FF',
          backgroundColor: '#fff'
        });
      }
}

三、总结:

⊙ 实际上只是切换了 class类名 gross 和 gross-dark

⊙ 使用Vuex的作用: 通过 this.setCurThemeType()传参 light 或者 drak, 然后将主题存在 state里面;方便任何组件使用;

⊙ 使用ximin()的作用:

因为每个页面都会使用到<view class="gross" :class="themeType==='dark' ? 'gross-dark':''">
所以直接在 mixin.js里面 引用了 Vuex, 并且把Getters 和 Mutations 存放在 computed 和 methods里面;
最后通过 Vue.mixin(themeMixin) 把这computed 和 methods混入到所有 Vue组件里面;
这样任何组件可以直接使用 computed 里面的 themeType.