Article directory
- I. Overview
- 2. Realization
-
- 2.1, `package.json`
- 2.2. `element-variables.scss`
- 2.3. `vuex` sets `store`
- 2.4. `ThemePicker` component
-
- 2.4.1、chalk.js
- 2.5. Import `header` into the page
- 2.6. Cache theme color
- 2.7. Use `css` variable for theme color
- 3. Finally
1. Overview
vue-element-admin
Official implementation principle: All styles afterelement-ui 2.0
version are written based onSCSS
, all colors They are all set based on several basic color variables, so it is not difficult to implement dynamic skin change. Just find those color variables and modify it. First, we need to get the version number ofelement-ui
throughpackage.json
, and request the corresponding style based on the version number. After getting the style, use regular matching and replacement to replace the color variable with what you need, and then dynamically add thestyle
tag to overwrite the originalcss
style.
You can click [Jump] for the online experience address. The specific effect is as follows:
2. Implementation
2.1, package.json
element-ui
fixed version, my project uses the 2.15.5
version, as shown below:
{ "dependencies": { "element-ui": "2.15.5" } }
2.2, element-variables.scss
Here is a no-brainer reference to the source code of vue-element-admin
. First, create a file named element-variables.scss
in the styles
folder. And introduce this file in main.js
.
/* src/styles/element-variables.scss */ /* Change theme color variables */ $--color-primary: #256DCB; $--color-success: #7AC800; $--color-danger: #EC4242; $--color-info: #999999; /* Change the icon font path variable, required */ $--font-path: '~element-ui/lib/theme-chalk/fonts'; @import "~element-ui/packages/theme-chalk/src/index"; /* If the exported variable value is undefined, the file name needs to be changed to element-variables.module.scss */ :export {<!-- --> theme: $--color-primary }
2.3, vuex
settings store
The above method has been able to achieve ElementUI
theme replacement, but it is far from enough to customize the color. Considering that the theme color is used in the entire project, we save it in In Vuex
, the next thing to do is to create a new settings.js
under store/modules
.
/* 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) // Cache it and retrieve it when refreshing // eslint-disable-next-line no-prototype-builtins if (state.hasOwnProperty(key)) {<!-- --> state[key] = value } } } const actions = {<!-- --> changeSetting ({<!-- --> commit }, data) {<!-- --> commit('CHANGE_SETTING', data) } } export default {<!-- --> namespaced: true, state, mutations, actions }
2.4, ThemePicker
component
This step is also a brainless copy of the source code of vue-element-admin
, and create a new component named ThemePicker
. The code is as follows:
/* src/components/ThemePicker/index.vue */ <template> <el-color-picker v-model="theme" :predefine=""['#409EFF', '#04A17E', '#304156','#212121','#A99711', '#13c2c2', '#6959CD', '#f5222d']" class="theme-picker" popper-class="theme-picker-dropdown" /> </template> <script> import { chalkCss } from './chalk.js' // It is the css obtained from the getCSSString interface. Here I fix the version number and cache the css locally. Remember to deal with the \ escaping problem // const version = require('element-ui/package.json').version // element-ui version from node_modules const ORIGINAL_THEME = '#409EFF' // default color primary color in chalk.js, based on this color a series of colors are calculated for regular replacement export default { name: 'ThemePicker', data () { return { chalk: '', // content of theme-chalk css theme: '' } }, computed: { defaultTheme () { return this.$store.state.settings.theme } }, watch: { defaultTheme: { handler: function (val, oldVal) { this.theme = val }, immediate: true }, async theme (val) { const oldVal = this.chalk ? this.theme : ORIGINAL_THEME if (typeof val !== 'string') return const themeCluster = this.getThemeCluster(val.replace('#', '')) const originalCluster = this.getThemeCluster(oldVal.replace('#', '')) console.log(themeCluster, originalCluster) const $message = this.$message({ message: this.$t('theme_compiling'), customClass: 'theme-message', type: 'success', duration: 0, iconClass: 'el-icon-loading' }) const getHandler = (variable, id) => { return () => { const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', '')) const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster) let styleTag = document.getElementById(id) if (!styleTag) { styleTag = document.createElement('style') styleTag.setAttribute('id', id) document.head.appendChild(styleTag) } styleTag.innerText = newStyle } } if (!this.chalk) { // const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css` // await this.getCSSString(url, 'chalk') this.chalk = chalkCss.replace(/@font-face{[^}] + }/, '') // Local cache, if you need to get online, use the above method. Advantages: no delay in switching. Disadvantages : Need to manually maintain css string } const chalkHandler = getHandler('chalk', 'chalk-style') chalkHandler() const styles = [].slice.call(document.querySelectorAll('style')) .filter(style => { const text = style.innerText return new RegExp(oldVal, 'i').test(text) & amp; & amp; !/Chalk Variables/.test(text) }) styles.forEach(style => { const { innerText } = style if (typeof innerText !== 'string') return style.innerText = this.updateStyle(innerText, originalCluster, themeCluster) }) this.$emit('change', val) $message.close() } }, methods: { updateStyle (style, oldCluster, newCluster) { let newStyle = style oldCluster.forEach((color, index) => { newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]) }) return newStyle }, getCSSString (url, variable) { return new Promise(resolve => { const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4 & amp; & amp; xhr.status === 200) { this[variable] = xhr.responseText.replace(/@font-face{[^}] + }/, '') resolve() } } xhr.open('GET', url) xhr.send() }) }, getThemeCluster (theme) { const tintColor = (color, tint) => { let red = parseInt(color.slice(0, 2), 16) let green = parseInt(color.slice(2, 4), 16) let blue = parseInt(color.slice(4, 6), 16) if (tint === 0) { // when primary color is in its rgb space return [red, green, blue].join(',') } else { red + = Math.round(tint * (255 - red)) green + = Math.round(tint * (255 - green)) blue + = Math.round(tint * (255 - blue)) red = red.toString(16) green = green.toString(16) blue = blue.toString(16) return `#${red}${green}${blue}` } } const shadeColor = (color, shade) => { let red = parseInt(color.slice(0, 2), 16) let green = parseInt(color.slice(2, 4), 16) let blue = parseInt(color.slice(4, 6), 16) red = Math.round((1 - shade) * red) green = Math.round((1 - shade) * green) blue = Math.round((1 - shade) * blue) red = red.toString(16) green = green.toString(16) blue = blue.toString(16) return `#${red}${green}${blue}` } const clusters = [theme] for (let i = 0; i <= 9; i + + ) { clusters.push(tintColor(theme, Number((i/10).toFixed(2)))) } clusters.push(shadeColor(theme, 0.1)) return clusters } } } </script> <style> .theme-message, .theme-picker-dropdown { z-index: 99999 !important; } .theme-picker .el-color-picker__trigger { height: 26px !important; width: 26px !important; padding: 2px; } .theme-picker-dropdown .el-color-dropdown__link-btn { display: none; } </style>
2.4.1, chalk.js
The chalk.js
mentioned above can be accessed through the URL https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css
Download the file corresponding to the element-ui
version. The downloaded file is css
, which needs to be converted into js
, as shown below:
export const chalkCss = '' // The string is the content of the downloaded index.css file, paste it all in
My chalk.js
file is here, click [Download]
2.5. Import header
into the page
Finally, use the ThemePicker
component in the page. Here I put it in header
.
//template <theme-picker @change="themeChange" /> // js import ThemePicker from '@/components/ThemePicker' // methods themeChange (val) { this.$store.dispatch('settings/changeSetting', { key: 'theme', value:val }) }
2.6, caching theme color
So far, all the dynamic skin changing functions have been implemented, but there is another problem: after refreshing the page, the theme color will be reset, so the theme color needs to be cached in localStore
when switching. Go, in order to load the theme color when any page is refreshed, I chose to add a ThemePicker
component to the App.vue
page. For the specific implementation, see the following code:
/* src/App.vue */ <template> <div id="app" :style="{'--color': defaultTheme}"> <theme-picker @change="themeChange" v-show="false" /> <router-view /> </div> </template> <script> import ThemePicker from '@/components/ThemePicker' export default { name: 'App', components: {ThemePicker}, computed: { defaultTheme () { return this.$store.state.settings.theme } }, mounted () { if (localStorage.getItem('theme')) { this.themeChange(localStorage.getItem('theme')) } }, methods: { themeChange (val) { this.$store.dispatch('settings/changeSetting', { key: 'theme', value:val }) } } } </script>
2.7. Use css
variables for theme colors
If you need to use theme colors for other self-defined styles, you can use css
variables, but you need to define the variables on root
in advance. I use vue
Two-way binding binds the theme color to :style="{'--color': defaultTheme}"
(see the code above for specific usage), so that the theme can be used under any component Colored (Note: This method is not supported by IE
browser), the code is as follows:
<div class="box"></div>
.box {<!-- --> width: 100px; height: 100px; background-color: var(--color); }
Tip:
- If the
scss
file exports an empty object, you need to change thescss
file name to the form ofxxx.module.scss
,CSS Modules
. - If you need to cache
chalkCss
,\
incss string
will be escaped. Remember to manually change it to\
. Otherwise, theicon
that comes withElementUI
cannot be displayed.
3. Finally
I code each article word by word, and I hope you guys can give me more opinions. Let’s do a three-click combo, likeCollectFollow. Creation is not easy, cheer me up, come on?