主题切换实现(vue-less)

介绍

  1. 本文适合黑白切换或者主题样式偏少的(建议:2-10种);主题越多,样式会越多。理论上无限套。
  2. 本文适合已经写好了一套主题,然后需求增加第二套或者多套主题(最好小于10套,当然也可以更多,但是样式也会更多)
  3. 本文以 vue + vue-cli2.x + element-ui +vuex举例
  4. 经过项目实战后建议直接使用css变量系列~请看我最后一点:

实现

  1. 您需要实现全局样式文件
    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最终如下图集成模式为下图
    在这里插入图片描述

  2. 在 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';
    
  3. 以黑白两种主题来介绍;
    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)
    	}
    }
    
  4. 挂载
    (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>
    
  5. 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');
    
  6. 引用示例

    <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>
    
    
  7. 此时如果你完成了以上步骤,则可以看到你的下拉框可以被覆盖颜色了
    在这里插入图片描述
    在这里插入图片描述

方式二:使用css变量实现本文功能;(推荐)

  1. 示例如下(/assets/style/theme.css)
:root[theme="light"] {
  --baseColor: white;
}
:root[theme="dark"] {
  --baseColor: black;
}
  1. 导入(vue直接再main里面导入,react顶级页面导入就行了)
  2. 使用
.box {
	color: var(--baseColor);
}
  1. 切换主题
// 切白色
window.document.documentElement.setAttribute('theme', 'light');
// 切黑色
window.document.documentElement.setAttribute('theme', 'dark');
  1. css变量可直接在js中赋值!
  2. css变量展示效果是双向绑定的。一变则都变~
  3. 如果实现主题方案,建议直接走css变量。

总结

  1. 如果实现主题方案,建议直接走css变量。简单易懂。
  2. 如果你有更好的实现方案,可以一起讨论~
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值