Vue + ElementUI 实现动态更换任意主题色(动态换肤)
admin
2024-02-16 02:41:25

最近基于 ElementUI 的项目上需要实现动态换肤的功能,这里提供两种方式:

  1. vue-element-admin 官方实现的方式
  2. webpack-theme-color-replacer 插件的实现方式

vue-element-admin 官方实现的方式

简单说明一下它的原理: element-ui 2.0 版本之后所有的样式都是基于 SCSS 编写的,所有的颜色都是基于几个基础颜色变量来设置的,所以就不难实现动态换肤了,只要找到那几个颜色变量修改它就可以了。 首先我们需要拿到通过 package.json 拿到 element-ui 的版本号,根据该版本号去请求相应的样式。拿到样式之后将样色,通过正则匹配和替换,将颜色变量替换成你需要的,之后动态添加 style 标签来覆盖原有的 css 样式。

  1. 这里无脑参考 vue-element-admin 的源码,首先现在 styles 文件夹下创建一个名为 element-variables.scss 文件,并在 main.js 中引入该文件。

    /* src/styles/element-variables.scss *//* 改变主题色变量 */
    $--color-primary: #256DCB;
    $--color-success: #7AC800;
    $--color-danger: #EC4242;
    $--color-info: #999999;/* 改变 icon 字体路径变量,必需 */
    $--font-path: '~element-ui/lib/theme-chalk/fonts';@import "~element-ui/packages/theme-chalk/src/index";/* 如遇到导出的变量值为 undefined 则本文件名需要改成 element-variables.module.scss */
    :export {theme: $--color-primary
    }
    
    /* main.js */import Vue from 'vue'
    import Element from 'element-ui'
    import './element-variables.scss'Vue.use(Element)
    
  2. 通过以上方式已经能够实现 ElementUI 主题替换了,但是想要做到自定义颜色还是远远不够的,考虑到主题色在整个项目中都有应用,所以我们将它存到 Vuex 中,接下来要做的就是在 store/modules 下新建 settings.js

    /* src/store/modules/settings.js */import variables from '@/styles/element-variables.module.scss'
    import * as Types from '../mutation-types'const state = {theme: variables.theme
    }const mutations = {CHANGE_SETTING: (state, { key, value }) => {localStorage.setItem('theme', value) // 缓存起来,刷新的时候重新取用// eslint-disable-next-line no-prototype-builtinsif (state.hasOwnProperty(key)) {state[key] = value}}
    }const actions = {changeSetting ({ commit }, data) {commit('CHANGE_SETTING', data)}
    }export default {namespaced: true,state,mutations,actions
    }
    
  3. 这一步也是无脑 copy vue-element-admin 的源码,新建一个名为 ThemePicker 的组件,代码如下:

    /* src/components/ThemePicker/index.vue */
    
  4. 最后在页面中使用 ThemePicker 组件,我这里是放到 header 里。

    // template
    
    // js
    import ThemePicker from '@/components/ThemePicker'
    // methods
    themeChange (val) {this.$store.dispatch('settings/changeSetting', {key: 'theme',value: val})
    }
    

到这里为止就已经实现了全部动态换肤的功能,不过还有一个问题就是刷新页面之后,主题色会重置,所以在切换的时候需要将主题色缓存到 localStore 中去,为了在任意页面刷新都可以加载主题色,我选择在 App.vue 页面也增加一个 ThemePicker 组件,具体实现见如下代码:

/* src/App.vue */

另外一些自己定义的样式如果需要用到主题色可以用 css 变量,但需要预先在 root 上定义好变量,我这里使用 vue 双向绑定将主题色绑定到 :style="{'--color': defaultTheme}" (具体用法见上面代码),这样就能在任何组件下使用该主题色了(注意:该方法 IE 浏览器不支持),代码如下:

.box {width: 100px;height: 100px;background-color: var(--color);
}

提示:

  1. 如果 scss 文件导出的是空对象,则需要将 scss 文件名称改成 xxx.module.scss 的形式,CSS Modules。
  2. 如果需要缓存 chalkCss 的,css string 中的 \ 会被转义,记得手动改成 \\,不然 ElementUI 自带的 icon 展示不出来。

参考文档:

  • vue-element-admin 动态换肤官方文档
  • ThemePicker 组件
  • CSS 变量

webpack-theme-color-replacer 插件的实现方式

此方式亲测可用,本质上也是颜色的替换,但是跟 ElementUI 稍稍有点兼容性问题,具体实现方式见 webpack-theme-color-replacer 的使用,我这里就不做过多赘述了。

相关内容

热门资讯

从山海古城到青春乐场,日照的滨... 中新网日照11月19日电(记者 左宇坤)深秋时节,山东日照莒县浮来山上的“天下银杏第一树”迎来一年中...
重构温泉体验:项目实践与发展路... 传统温泉同质化、体验形式单一的问题日益凸显,难以满足当下游客对个性化、沉浸式、多功能消费的需求。随着...
原创 非... 面对急需帮助的人,我们会先选择帮助,还是先拍照呢?如果这是发生在10年前,肯定不用多想,大家一定会第...
原创 非... 茶馓又名油面、馓子,是江苏知名传统点心,其中以淮安茶馓最富胜名。 01 追溯历史 淮安茶馓起源于战国...