Blame view

src/components/Theme/theme.vue 5.55 KB
1 2 3 4 5
<!--
 * @Description: 
 * @Autor: renchao
 * @LastEditTime: 2023-07-25 16:09:09
-->
任超 committed
6 7 8 9 10 11 12
<template>
  <el-color-picker v-model="theme"
    :predefine="['#409EFF', '#1890ff', '#304156', '#212121', '#11a983', '#13c2c2', '#6959CD', '#f5222d',]"
    class="theme-picker" popper-class="theme-picker-dropdown" />
</template>

<script>
13 14 15 16 17 18 19 20 21
  const version = require('element-ui/package.json').version // element-ui version from node_modules
  const ORIGINAL_THEME = '#409EFF' // default color

  export default {
    data () {
      return {
        chalk: '', // content of theme-chalk css
        theme: ''
      }
任超 committed
22
    },
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    computed: {
      defaultTheme () {
        return this.$store.state.app.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: '  Compiling the theme',
          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
任超 committed
62 63 64
          }
        }

65 66 67 68
        if (!this.chalk) {
          const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
          await this.getCSSString(url, 'chalk')
        }
任超 committed
69

70
        const chalkHandler = getHandler('chalk', 'chalk-style')
任超 committed
71

72
        chalkHandler()
任超 committed
73

74 75 76 77 78 79 80 81 82
        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 (typeof innerText !== 'string') return
          style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
任超 committed
83 84
        })

85
        this.$emit('change', val)
任超 committed
86

87 88
        $message.close()
      }
任超 committed
89 90
    },

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    methods: {
      /**
       * @description: updateStyle
       * @param {*} style
       * @param {*} oldCluster
       * @param {*} newCluster
       * @author: renchao
       */
      updateStyle (style, oldCluster, newCluster) {
        let newStyle = style
        oldCluster.forEach((color, index) => {
          newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
        })
        return newStyle
      },

      /**
       * @description: getCSSString
       * @param {*} url
       * @param {*} variable
       * @author: renchao
       */
      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()
        })
      },

      /**
       * @description: getThemeCluster
       * @param {*} theme
       * @author: renchao
       */
      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}`
任超 committed
150 151 152
          }
        }

153 154 155 156 157 158 159 160
        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)
任超 committed
161 162 163 164 165 166 167 168

          red = red.toString(16)
          green = green.toString(16)
          blue = blue.toString(16)

          return `#${red}${green}${blue}`
        }

169 170 171 172 173 174
        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
任超 committed
175 176 177 178 179 180
      }
    }
  }
</script>

<style>
181 182 183 184 185 186 187 188 189 190 191 192 193 194
  .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;
  }
yuanbo committed
195
</style>