介绍
- 本文适合黑白切换或者主题样式偏少的(建议:2-10种);主题越多,样式会越多。理论上无限套。
- 本文适合已经写好了一套主题,然后需求增加第二套或者多套主题(最好小于10套,当然也可以更多,但是样式也会更多)
- 本文以 vue + vue-cli2.x + element-ui +vuex举例
实现
-
您需要实现全局样式文件
1)在/src/main.js
引入全局样式文件;如果有使用插件实现全局样式引入的则,只需要确保你的全局样式文件可以覆盖掉 UI 组件的样式import Vue from 'vue' import App from './App' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css'; import "./styles/index.less"; new Vue({ render: h => h(App), data: { eventHub: new Vue() } }).$mount('#app');
2)个人建议在
src文件夹
下创建一个styles文件夹
来管理全局样式。因为这块可以使用less的mixin来抽离成样式组件。
3)styles最终如下图集成模式为下图
-
在 styles 文件夹中增加 index.less、theme.less、allVar.js、allVar.less 四个文件;theme、components两个文件夹。(如上图)
1)index.less
;主入口@import './theme.less';
2)
theme.less
; 负责引入主题中的index.less文件@import './theme/White/index.less'; // 白色主题 @import './theme/Black/index.less'; // 黑色主题
3)
allVar.js
;你的所有主题都需要在这里引入,主要是负责js中使用less变量(颜色、字体大小等)而存在的import black from '@/styles/anHui-new/theme/Black/var.less'; import white from '@/styles/anHui-new/theme/White/var.less'; // 获取 less 变量颜色 export default { black, white }
4)
allVar.less
;集合所有主题中的变量文件,如果后续需要在页面内使用主题变量的话(非常不建议在页面内使用!因为会使后续增加主题提高难度!)@import './theme/Black/var.less'; @import './theme/White/var.less';
-
以黑白两种主题来介绍;
1)src/styles/theme中增加 Black 和 White 两个文件夹;并且同时增加 index.less 和 var.less文件;建议在文件夹中再次增加components文件夹;如下图
2)此时theme中每一个文件夹则是一种主题色的配置;我们以黑色 Black (style/theme/Black) 来举例子:
(1)Black/index.less
;@import './var.less'; // 引入当前主题的变量 @import '../../components/FontColor/index.less'; // 全局引入修改字体颜色的less方法(mixin) @import '../../components/Select/index.less'; // 引入下拉框的less方法(mixin实现) .theme-black-731514100-random { .el-select-dropdown(@select-bg-color: @black-select-bg-color, @select-border-color: @black-select-border-color); }
(2)
Black/var.less
;命名规范建议以主题色为开头(比如@black-xxxxx;@white-xxxxx)// 基础色 @black-base-color: #0080FF; @black-base-bg-pop-color: rgba(0, 13, 26, .8); // 下拉框 @black-select-border-color: #00D5FF; @black-select-bg-color: @black-base-bg-pop-color; :export { base-color: @black-base-color; base-bg-pop-color: @black-base-bg-pop-color; }
温馨提示1:上文中的
:export
为less文件的导出变量;可以直接在 js 中使用颜色;(直接import xxx from 'styles/theme/Black/var.less’即可看到已经编译好的对象)
温馨提示2:目前没有发现可以直接导出当前less文件全部变量。只能自己手动导出变量;
温馨提示3:导出变量一定要与上面一样;因为在vuex可以直接切换主题名字进行切换主题,到时候选取的变量名要保持一致!3)此时你会发现我引入了 components 中的两个 less 组件内容;那么我们开始介绍这两个组件;
(1)切换到 components 目录(src/styles/components);增加两个文件夹:Select、FontColor;文件夹中都含有个index.less;如下图:
(2)FontColor和Select都是使用less的mixin抽成为方法了;如果不了解的话可以去 less 官网看看 mixin 如何使用
(3)FontColor/index.less
;修改字体颜色的.changeFontColor(@color) { color: @color; a, span, div, label, i { color: @color; } } .changeFontColorImportant(@color) { color: @color !important; a, span, div, label, i { color: @color !important; } }
(4)
Select/index.less
;全局修改下拉框样式组件.el-select-activeClass(@select-border-color) { background: transparent !important; .changeFontColor(@select-border-color); // 这个是因为外部引入了 FontColor 组件的原因; } .el-select-dropdown(@select-bg-color, @select-border-color) { background: @select-bg-color; border: 1px solid @select-border-color; .popper__arrow::after { border-bottom-color: @select-border-color; } .selected { .el-select-activeClass(@select-border-color) } .hover { .el-select-activeClass(@select-border-color) } }
-
挂载
(1)增加文件:src/mixin/theme.js
import { mapGetters, mapMutations } from 'vuex'; export default { computed: { ...mapGetters('style', ['theme']) }, watch: { theme() { this.setTheme(); } }, mounted() { this.setTheme() }, methods: { ...mapMutations('style', ['changeTheme']), setTheme() { document.getElementsByTagName('body')[0].className = `theme-${this.theme}-731514100-random` }, } }
(2)在你页面的主入口混入(mixins)
src/mixin/theme.js
这个文件;比如说(app.vue中)<template> <div id="app" style="height:100%"> <router-view></router-view> </div> </template> <script> import themeMixin from "@/mixin/theme.js"; export default { name: 'App', mixins: [ /** themeMixin: 主题挂载 * @computed theme * @method setTheme * @watch theme */ themeMixin ], } </script>
-
vuex状态管理数据,实现切换主题功能,实现获取less变量值功能;
(1)使用vuex状态管理;创建文件:src/store/modules/style.js
;此处使用到了命名空间,如果对命名空间不理解的话可以去vuex官网看看。(namespaced: true为开启命名空间)import style from '@/styles/anHui-new/allVar.js'; export default { namespaced: true, state: { themeList: [ { type: 'white', style: style.white }, { type: 'black', style: style.black } ], theme: 'black' }, mutations: { changeTheme(state, data) { // 改变主题调用此函数;唯一参数:传递改变为哪个主题、或者在第一个和第二个主题切换。 state.theme = data || state.themeList.reduce((pre, next, i, arr) => { if (pre) return pre; if (next.type !== state.theme) pre = next.type; return pre }, void 0) } }, getters: { theme: (state) => state.theme, // 获取当前主题是哪个 globalColor: (state) => (style[state.theme]) // 会返回你定义的对象-返回当前主题的变量颜色 } }
温馨提示:上面这个文件需要挂载到vuex里面去;如果已经挂载过了则不需要走以下不走了;实现如下:
(2)挂载到vuex中(src/store/index.js)import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex) let moduleInclude = { state: { }, actions: { }, mutations: { } } const modulesFiles = require.context('./modules', true, /\.js$/) const modules = modulesFiles.keys().reduce((modules, modulePath) => { const name = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1'), value = modulesFiles(modulePath); modules[name] = value.default; return modules; }, {}) export default new Vuex.Store({ modules: { moduleInclude, ...modules } })
(3)在 src/main.js 中挂到 vue 中
import Vue from 'vue' import App from './App' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css'; import store from './store'; // 这个是挂载vuex的 import "./styles/index.less"; new Vue({ store, render: h => h(App), data: { eventHub: new Vue() } }).$mount('#app');
-
引用示例
<template> <div> <button @click="changeTheme()">changeTheme</button> <!-- 这里写你的下拉框组件去测试吧 --> </div> </template> <script> import { mapGetters, mapMutations } from "vuex"; import themeMixin from "@/mixin/theme.js"; export default { data() { return { }; }, mixins: [ /** themeMixin: 主题挂载 * @computed theme * @method setTheme * @watch theme */ themeMixin, ], computed: { ...mapGetters("style", ["theme"]), }, methods: { ...mapMutations("style", ["changeTheme"]) }, }; </script>
-
此时如果你完成了以上步骤,则可以看到你的下拉框可以被覆盖颜色了
总结
- 功能持续加强版:可集成一个项目模块,专门来配置项目主题色。最后生成样式配置文件。(src/styles/theme/xxxxxx: index.less 和 var.less);
- 切换主题这功能好像可以使用
css-vars-ponyfill
这个插件更好的去实现样;有兴趣的小伙伴可以去研究一下(期待你的回信);css-vars-ponyfill官网地址 - 如果你有更好的实现方案,可以一起讨论~