项目中需要做一个全局换肤(主题色)以及多语言的需求,在通用页更改,全局生效。
我们都知道,vue是MVVM模式,即模型-视图-视图模型,视图更新,数据会跟着更新,反之也一样。但是仅仅在当前组件生效,那么:
如何在一处修改数据就能触发全局视图的更新呢?
答案就是vuex状态管理。
有了状态管理,如何将主题色,语言数据等注入每一个组件呢?
我们可以用mixin(混入),单组件混入或全局混入都可,可以根据需要权衡是否使用全局混入,全局混入意味着每一个new出来的组件,都会拥有混入的方法和数据,并且优先级是组件内部所声明的数据或方法>混入的
下面我们就来进入正题,以uni-app为例
首先,在项目根路径下新建store文件夹,并在store目录下新建module文件夹,添加主题色theme.js和多语言lang.js的配置文件
lang.js
let userLang , lang = {};
try {
// 1. 分析用户已经选择的语言
userLang = uni.getStorageSync("userLang");
// 2. 如果用户没有选择过则设置默认语言
if(!userLang){
userLang = 'zh'
}
switch(userLang.substring(0, 2)) {
case 'zh':
lang = require('../../lang/zh.js');
break;
case 'en':
lang = require('../../lang/en.js');
break;
case 'ja':
lang = require('../../lang/ja.js');
break;
default:
lang = require('../../lang/zh.js');
}
} catch (e) {
// error
}
const state = {
lang : lang
}
const mutations={
changeLang(state, lang) {
state.lang = lang;
}
}
const actions = {
changeLang: function(context){
let lang = {};
uni.showActionSheet({
itemList:['简体中文', 'English', '日本語'],
success: function(e){
try {
if (e.tapIndex == 0) {
uni.setStorageSync('userLang', 'zh');
lang = require('../../lang/zh.js');
} else if (e.tapIndex == 1){
uni.setStorageSync('userLang', 'en');
lang = require('../../lang/en.js');
} else {
uni.setStorageSync('userLang', 'ja');
lang = require('../../lang/ja.js');
}
} catch (e) {
// error
}
context.commit('changeLang', lang);
}
});
}
}
export default {
namespaced: true, // 当你需要在别的文件里面使用( mapGetters、mapActions)时
state,
actions,
mutations
}
theme.js
let defaultColor;
try {
// 获取用户已设置的主题色
defaultColor = uni.getStorageSync("themeColor");
// 如果没有,设置默认色
if(!defaultColor){
defaultColor = '#40aee2';
}
} catch (e) {
// error
}
const state = {
themeColor: defaultColor, // 初始化为配置的主题色
};
const mutations = {
setThemeColor(state, color) {
state.themeColor = color;
}
};
const actions = {
setThemeColor(context, color) { // 触发mutations里面的setThemeColor ,传入数据形参color
let themeColor = '';
uni.showActionSheet({
itemList: ['红色', '橙色'],
success: function(e) {
if (e.tapIndex == 0) {
themeColor = '#f25762';
} else {
themeColor = '#ff6600';
}
uni.setStorageSync('themeColor', themeColor);
context.commit('setThemeColor', themeColor);
}
});
}
};
export default {
namespaced: true, // 当你需要在别的文件里面使用( mapGetters、mapActions)时
state,
actions,
mutations
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import themeColor from './modules/theme'
import lang from './modules/lang'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
modules: {
themeColor,
lang
},
//在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
strict: debug
})
然后在项目入口文件中引入并挂载
main.js
import Vue from 'vue'
import App from './App'
import store from "./store"
import { mapState } from 'vuex'
// 全局混入主题色,多语言
Vue.mixin({
computed: {
...mapState('lang', {
lang: 'lang'
}),
...mapState('themeColor', {
themeColor: 'themeColor'
})
}
})
Vue.config.productionTip = false
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
store,
...App
})
app.$mount()
在index.vue中使用
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{lang.hello}}</text>
</view>
<navigator open-type="navigate" url="./test">
<button class="button" :style="{background: themeColor}">去更换主题色和语言</button>
</navigator>
</view>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
在test.js中设置
<template>
<view>
<view class="list">
<view class="items" @tap="changeLang">
<view class="body">
<view class="title">多语言<text>跟随系统</text></view>
</view>
</view>
<view class="items" @tap="setThemeColor">
<view class="body">
<view class="title">使用默认皮肤<text>选择皮肤</text></view>
</view>
</view>
</view>
</view>
</template>
<script>
import {mapActions} from 'vuex';
export default {
methods: {
...mapActions('lang', {
'changeLang': 'changeLang'
}),
...mapActions('themeColor', {
'setThemeColor': 'setThemeColor'
})
}
}
</script>
以上只是提供一个简单的示例,具体的实现细节可以自己修改。
其他文件:
lang/zh.js
module.exports = {
hello: '你好'
}