Implemented functions

1. After switching the skin, the login page displays different background pictures, font colors, and the background color of the selected state.

2. The introduced elementUI component is also switched to the corresponding theme color.

3. Through the VUex state manager, store the currently selected theme properties (including background color, font color, selected state color, etc.). Can be configured according to different requirements). In any component, the subject property can be called through the Store. Also, the theme properties can be called directly from within the CSS file.

SwitchSkin component code for switching themes

<template> <! -- Theme Style selector --><div class="theme-picker">
    <div
      class="selected-theme webkit-transition"
      :style="{ background: selectedColor || themeSelectedColor }"
    >
      <div class="logo">
        <img src="static/img/theme/skin.png" alt="" />
      </div>
      <div class="text">Switch the skin</div>
    </div>
    <div
      v-for="(item, index) in themeColorList"
      :key="index"
      class="theme-item"
      @click="themeChange(item.color)"
    >
      <div class="bg" :style="{ background: item.color + '4d' }" />
      <div class="color" :style="{ background: item.color }">
        <img
          v-show="item.color == selectedColor"
          src="static/img/theme/check.png"
          alt=""
        />
      </div>
      <div class="text">
        {{ item.text }}
      </div>
    </div>
  </div>
</template>
​
<script>
import { ThemeChangeMixin } from "@/mixins/ThemeChangeMixin";
export default {
  name: "".components: {},
  mixins: [ThemeChangeMixin],
  props: {},
  data() {
    return {};
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {}}; </script><style lang="scss" scoped>
/* Theme style selection */
.theme-picker {
  position: absolute;
  right: 0;
  width: 40px;
  height: 40px;
  top: 80px;
  font-size: 14px;
  border-radius: 7px 0 0 7px;
  overflow: hidden;
  -webkit-transition: all 1s ease 0.1 s;
  -o-transition: all 1s ease 0.1 s;
  -moz-transition: all 1s ease 0.1 s;
  transition: all 1s ease 0.1 s;
  &:hover {
    width: 118px;
    right: 0;
    height: 120px;
    .selected-theme {
      .text {
        display: block; }}}.selected-theme {
    display: flex;
    align-items: center;
    height: 40px;
    cursor: pointer;
    .logo {
      width: 16px;
      height: 16px;
      margin: 3px 9px 0 12px;
      -webkit-animation: swing 3s;
      -webkit-animation-iteration-count: 3;
      -webkit-animation-delay: 3s;
    }
    .text {
      display: none;
      color: #fff;
      width: 100%;
      text-align: left; }}.theme-item {
    display: flex;
    align-items: center;
    height: 40px;
    border: 1px solid #e5e5e5;
    background: #fff;
    cursor: pointer;
    &:hover {
      // background: #e4e6f4 ! important;
      .bg {
        opacity: 1; }} &:last-child {
      border: none;
    }
    .bg {
      height: 40px;
      width: 100%;
      position: absolute;
      opacity: 0;
    }
    .color {
      width: 16px;
      height: 16px;
      margin: 0 9px 0 12px;
      padding: 8px;
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 4px;
      img {
        width: 11px;
        height: 10px;
        display: block;
        position: absolute;
        left: 3px;
        top: 3px; }}.text {
      color: # 757575;
      width: 100%;
      text-align: left; }}}</style>
Copy the code

Css3 property gradient

Over the selector, the theme selection drop-down box expands. Use cSS3-webkit-Transition to create a soft gradient.

.theme-picker {
  position: absolute;
  right: 0;
  width: 40px;
  height: 40px;
  top: 80px;
  font-size: 14px;
  border-radius: 7px 0 0 7px;
  overflow: hidden;
  -webkit-transition: all 1s ease 0.1 s;
  -o-transition: all 1s ease 0.1 s;
  -moz-transition: all 1s ease 0.1 s;
  transition: all 1s ease 0.1 s;
  &:hover {
    width: 118px;
    right: 0;
    height: 120px;
    .selected-theme {
      .text {
        display: block; }}}}Copy the code

“Mixin” files

import { ThemeChangeMixin } from "@/mixins/ThemeChangeMixin";
export default {
  name: "".components: {},
  mixins: [ThemeChangeMixin],
  props: {},
  data() {
    return {};
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {}};Copy the code

The data for the theme skin, and how to switch themes, is in the ThemeChangeMixin file. As a mixin object, used in components that switch themes.

The mixin website has a detailed explanation

Cn.vuejs.org/v2/guide/mi…

The themeColorList array of topic options

 themeColorList: [
      {
        color: '#3E50B3'.text: 'blue'.skin: {
          themeImg: 'blue'.themeBgColor: '#D7DBEA'.themeNavColor: '#6573C4'.botColor: 'white'}}, {color: '#CD2E18'.text: 'red'.skin: {
          themeImg: 'red'.themeBgColor: '#FAEAE8'.themeNavColor: '#DA523E'.botColor: 'black'}}]Copy the code

Vuex state manager, switch topics

The way to switch themes is as follows. After switching themes, change the current theme state through the state manager Vuex.

 /* Switch the theme */
themeChange(val) {
  if (this.selectedColor == val) return
  this.selectedColor = val
  this.$store.dispatch('settings/changeSetting', {
    key: 'theme'.value: val
  })
  const list = this.themeColorList
  const idx = list.findIndex((item) = > item.color == val)
  Object.keys(list[0] ['skin']).forEach((item) = > {
    const value = list[idx]['skin'][item]
    this.$store.dispatch('settings/changeSetting', {
      key: item,
      value
    })
  })
  this.changeElementTheme(val)
},
Copy the code

Settings. Js in the Modules store folder of Vuex configures the subjects-related state, mutations and Actions objects.

I have a very detailed article on the VUEX configuration.

const state = {
  theme: '#3E50B3'.themeBgColor: '#D7DBE'.themeNavColor: '#6573C4'.themeImg: 'blue'.botColor: 'white'.websiteName: "".// System name
  copyright: "".companyLogo: "",}const mutations = {
  CHANGE_SETTING: (state, { key, value }) = > {
    // 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
}
Copy the code

Switch to the elementUI theme

In the changeElementTheme method, load the different elementUI theme color files.

ThemeChangeMixin. Js file


/** Toggle skins and change the theme of mixin */
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // deexport const ThemeChangeMixin = {
  data() {
    return {
      chalk: ' '.// content of theme-chalk css
      selectedColor: ' '.themeSelectedColor: this.$store.state.settings.theme,
      themeColorList: [{color: '#3E50B3'.text: 'blue'.skin: {
            themeImg: 'blue'.themeBgColor: '#D7DBEA'.themeNavColor: '#6573C4'.botColor: 'white'}}, {color: '#CD2E18'.text: 'red'.skin: {
            themeImg: 'red'.themeBgColor: '#FAEAE8'.themeNavColor: '#DA523E'.botColor: 'black'}}]}},created() {
    this.selectedColor = this.themeSelectedColor
  },
  methods: {
    /* Switch the theme */
    themeChange(val) {
      if (this.selectedColor == val) return
      this.selectedColor = val
      this.$store.dispatch('settings/changeSetting', {
        key: 'theme'.value: val
      })
      const list = this.themeColorList
      const idx = list.findIndex((item) = > item.color == val)
      Object.keys(list[0] ['skin']).forEach((item) = > {
        const value = list[idx]['skin'][item]
        this.$store.dispatch('settings/changeSetting', {
          key: item,
          value
        })
      })
      this.changeElementTheme(val)
    },
    async changeElementTheme(val) {
      const oldVal = this.chalk ? this.themeSelectedColor : ORIGINAL_THEME
      if (typeofval ! = ='string') return
      const themeCluster = this.getThemeCluster(val.replace(The '#'.' '))
      const originalCluster = this.getThemeCluster(oldVal.replace(The '#'.' '))
      const getHandler = (variable, id) = > {
        return () = > {
          const originalCluster = this.getThemeCluster(
            ORIGINAL_THEME.replace(The '#'.' '))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')}const that = this
      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) && !/Chalk Variables/.test(text)
          )
        })
      styles.forEach((style) = > {
        const { innerText } = style
        if (typeofinnerText ! = ='string') return
        style.innerText = this.updateStyle(
          innerText,
          originalCluster,
          themeCluster
        )
      })
    },
    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 && 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
    }
  }
}
Copy the code

CSS var () function

Above, change the theme color through JS. So, can I use the theme color directly in the CSS file? The answer is yes, with the CSS var() function.

I introduced the theme colors in the app.vue file as follows, including the background color, the theme image, the bottom color, and so on. It can be configured according to specific requirements.

<template>
  <div
    id="app"
    :style="{ '--themeColor': theme, '--themeBgColor': themeBgColor, '--themeNavColor': themeNavColor, '--themeImg': themeImg, '--botColor': botColor, }"
  >
    <router-view />
  </div>
</template>
Copy the code

This property can then be called from within the CSS file via the CSS var function

.name{&:hover {
      color: var(--themeColor);
      transform: scale(1.1); }}Copy the code

App.vue complete code


<template>
  <div
    id="app"
    :style="{ '--themeColor': theme, '--themeBgColor': themeBgColor, '--themeNavColor': themeNavColor, '--themeImg': themeImg, '--botColor': botColor, }"
  >
    <router-view />
  </div>
</template>
​
<script>
import { ThemeChangeMixin } from '@/mixins/ThemeChangeMixin'const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // deexport default {
  name: 'App'.mixins: [ThemeChangeMixin],
  computed: {
    theme() {
      return this.$store.state.settings.theme
    },
    themeBgColor(){
      return this.$store.state.settings.themeBgColor
    },
    themeNavColor(){
      return this.$store.state.settings.themeNavColor
    },
    themeImg() {
      return this.$store.state.settings.themeImg
    },
    botColor() {
      return this.$store.state.settings.botColor
    }
  },
  mounted() {
    this.handleUserTheme()
  },
  methods: {
    async handleUserTheme() {
      const val = this.theme
      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
      if (typeofval ! = ='string') return
      const themeCluster = this.getThemeCluster(val.replace(The '#'.' '))
      const originalCluster = this.getThemeCluster(oldVal.replace(The '#'.' '))
      const getHandler = (variable, id) = > {
        return () = > {
          const originalCluster = this.getThemeCluster(
            ORIGINAL_THEME.replace(The '#'.' '))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')}const that = this
      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) && !/Chalk Variables/.test(text)
          )
        })
      styles.forEach((style) = > {
        const { innerText } = style
        if (typeofinnerText ! = ='string') return
        style.innerText = this.updateStyle(
          innerText,
          originalCluster,
          themeCluster
        )
      })
    }
  }
}
Copy the code