zoukankan      html  css  js  c++  java
  • vue 官方换肤实现

    演示地址:

    https://elementui.github.io/theme-chalk-preview/#/zh-CN

    原理:

    element ui 2.0版本之后是基于scss实现的,所有到颜色都是通过变量进行定义,所以我们可以通过修改变量来达到动态换肤的目的.

    代码:

    1.换肤组件:

    ThemePicker

      1 <template>
      2   <el-color-picker
      3     v-model="theme"
      4     :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
      5     class="theme-picker"
      6     popper-class="theme-picker-dropdown"
      7   />
      8 </template>
      9 
     10 <script>
     11 const version = require('element-ui/package.json').version // element-ui version from node_modules
     12 const ORIGINAL_THEME = '#409EFF' // default color
     13 
     14 export default {
     15   data() {
     16     return {
     17       chalk: '', // content of theme-chalk css
     18       theme: ''
     19     }
     20   },
     21   computed: {
     22     defaultTheme() {
     23       return this.$store.state.settings.theme
     24     }
     25   },
     26   watch: {
     27     defaultTheme: {
     28       handler: function(val, oldVal) {
     29         this.theme = val
     30       },
     31       immediate: true
     32     },
     33     async theme(val) {
     34       const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
     35       if (typeof val !== 'string') return
     36       const themeCluster = this.getThemeCluster(val.replace('#', ''))
     37       const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
     38       console.log(themeCluster, originalCluster)
     39 
     40       const $message = this.$message({
     41         message: '  Compiling the theme',
     42         customClass: 'theme-message',
     43         type: 'success',
     44         duration: 0,
     45         iconClass: 'el-icon-loading'
     46       })
     47 
     48       const getHandler = (variable, id) => {
     49         return () => {
     50           const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
     51           const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
     52 
     53           let styleTag = document.getElementById(id)
     54           if (!styleTag) {
     55             styleTag = document.createElement('style')
     56             styleTag.setAttribute('id', id)
     57             document.head.appendChild(styleTag)
     58           }
     59           styleTag.innerText = newStyle
     60         }
     61       }
     62 
     63       if (!this.chalk) {
     64         const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
     65         await this.getCSSString(url, 'chalk')
     66       }
     67 
     68       const chalkHandler = getHandler('chalk', 'chalk-style')
     69 
     70       chalkHandler()
     71 
     72       const styles = [].slice.call(document.querySelectorAll('style'))
     73         .filter(style => {
     74           const text = style.innerText
     75           return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
     76         })
     77       styles.forEach(style => {
     78         const { innerText } = style
     79         if (typeof innerText !== 'string') return
     80         style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
     81       })
     82 
     83       this.$emit('change', val)
     84 
     85       $message.close()
     86     }
     87   },
     88 
     89   methods: {
     90     updateStyle(style, oldCluster, newCluster) {
     91       let newStyle = style
     92       oldCluster.forEach((color, index) => {
     93         newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
     94       })
     95       return newStyle
     96     },
     97 
     98     getCSSString(url, variable) {
     99       return new Promise(resolve => {
    100         const xhr = new XMLHttpRequest()
    101         xhr.onreadystatechange = () => {
    102           if (xhr.readyState === 4 && xhr.status === 200) {
    103             this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
    104             resolve()
    105           }
    106         }
    107         xhr.open('GET', url)
    108         xhr.send()
    109       })
    110     },
    111 
    112     getThemeCluster(theme) {
    113       const tintColor = (color, tint) => {
    114         let red = parseInt(color.slice(0, 2), 16)
    115         let green = parseInt(color.slice(2, 4), 16)
    116         let blue = parseInt(color.slice(4, 6), 16)
    117 
    118         if (tint === 0) { // when primary color is in its rgb space
    119           return [red, green, blue].join(',')
    120         } else {
    121           red += Math.round(tint * (255 - red))
    122           green += Math.round(tint * (255 - green))
    123           blue += Math.round(tint * (255 - blue))
    124 
    125           red = red.toString(16)
    126           green = green.toString(16)
    127           blue = blue.toString(16)
    128 
    129           return `#${red}${green}${blue}`
    130         }
    131       }
    132 
    133       const shadeColor = (color, shade) => {
    134         let red = parseInt(color.slice(0, 2), 16)
    135         let green = parseInt(color.slice(2, 4), 16)
    136         let blue = parseInt(color.slice(4, 6), 16)
    137 
    138         red = Math.round((1 - shade) * red)
    139         green = Math.round((1 - shade) * green)
    140         blue = Math.round((1 - shade) * blue)
    141 
    142         red = red.toString(16)
    143         green = green.toString(16)
    144         blue = blue.toString(16)
    145 
    146         return `#${red}${green}${blue}`
    147       }
    148 
    149       const clusters = [theme]
    150       for (let i = 0; i <= 9; i++) {
    151         clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
    152       }
    153       clusters.push(shadeColor(theme, 0.1))
    154       return clusters
    155     }
    156   }
    157 }
    158 </script>
    159 
    160 <style>
    161 .theme-message,
    162 .theme-picker-dropdown {
    163   z-index: 99999 !important;
    164 }
    165 
    166 .theme-picker .el-color-picker__trigger {
    167   height: 26px !important;
    168    26px !important;
    169   padding: 2px;
    170 }
    171 
    172 .theme-picker-dropdown .el-color-dropdown__link-btn {
    173   display: none;
    174 }
    175 </style>

    该组件将选择到颜色保存到vuex的state中, 代码: "this.$store.state.settings.theme"

    2.添加store/modules/setting.js文件

     1 import variables from '@/styles/element-variables.scss'
     2 
     3 const state = {
     4   theme: variables.theme
     5 }
     6 
     7 const mutations = {
     8   CHANGE_SETTING: (state, { key, value }) => {
     9     if (state.hasOwnProperty(key)) {
    10       state[key] = value
    11     }
    12   }
    13 }
    14 
    15 const actions = {
    16   changeSetting({ commit }, data) {
    17     commit('CHANGE_SETTING', data)
    18   }
    19 }
    20 
    21 export default {
    22   namespaced: true,
    23   state,
    24   mutations,
    25   actions
    26 }

    setting.js中默认主题是引入的'@/styles/element-variables.scss'

    3. 添加element-variables.scss

     1 /**
     2 * I think element-ui's default theme color is too light for long-term use.
     3 * So I modified the default color and you can modify it to your liking.
     4 **/
     5 
     6 /* theme color */
     7 $--color-primary: #1890ff;
     8 $--color-success: #13ce66;
     9 $--color-warning: #FFBA00;
    10 $--color-danger: #ff4949;
    11 // $--color-info: #1E1E1E;
    12 
    13 $--button-font-weight: 400;
    14 
    15 // $--color-text-regular: #1f2d3d;
    16 
    17 $--border-color-light: #dfe4ed;
    18 $--border-color-lighter: #e6ebf5;
    19 
    20 $--table-border:1px solid#dfe6ec;
    21 
    22 /* icon font path, required */
    23 $--font-path: '~element-ui/lib/theme-chalk/fonts';
    24 
    25 @import "~element-ui/packages/theme-chalk/src/index";
    26 
    27 // the :export directive is the magic sauce for webpack
    28 // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
    29 :export {
    30   theme: $--color-primary;
    31 }

    element-variables.scss 文件通过:export将theme导出,这样就能像使用js变量一样使用scss变量了,
    准备工作就绪,开始测试

    4.添加测试代码

     1 <template>
     2   <!-- 添加全局样式 -->
     3   <div>
     4     <div>
     5       <div class="test-theme">
     6         <el-button type="primary" />
     7       </div>
     8       <br>
     9       <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
    10     </div>
    11   </div>
    12 </template>
    13 <script>
    14 import ThemePicker from '@/components/ThemePicker'
    15 export default {
    16   name: 'App',
    17   components: {
    18     ThemePicker
    19   },
    20   data() {
    21     return {
    22       msg: 'Dynamic Themes',
    23       theme: 'default',
    24     }
    25   },
    26   methods: {
    27     themeChange(val) {
    28       this.$store.dispatch('settings/changeSetting', {
    29         key: 'theme',
    30         value: val
    31       })
    32     }
    33   }
    34 }

    大功告成!

    优点: 可以动态改变主色调
    缺点: 没有足够的个性化,仅仅能修改一些基本的配色

  • 相关阅读:
    go,指针
    go ,字符串的编码及如何统计字符长度,
    go中的map,如python中的字典
    go 可变长参数的应用
    go 数组切片
    Django 模板层
    Django的路由层和视图层
    Django
    Django简介
    JQurey
  • 原文地址:https://www.cnblogs.com/atomgame/p/12496572.html
Copyright © 2011-2022 走看看