• Vue管理系统前端系列五自定义主题



    自定义主题

    1.安装「主题生成工具」

    由于主题工具需要依赖于 node-sass,而node-sass版本兼容性并不好,对应 node 版本可能不兼容直接执行npm i element-theme -g所安装的版本,因此需要自行先安装对应 node 版本的node-sass.

    对应版本如下

    NodeJS Minimum node-sass version Node Module
    Node 14 4.14+ 83
    Node 13 4.13+ 79
    Node 12 4.12+ 72
    Node 11 4.10+ 67
    Node 10 4.9+ 64
    Node 8 4.5.3+ 57

    因为我这里的 node 版本是 12.18.1

    # 先安装node-sass
    set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/
    
    npm install node-sass@4.12.0 --save
    
    npm i element-theme -g
    
    

    特别说明: 若出现 gyp verb check python checking for Python executable "python" in the PATH 错误时。可执行,出现 all done 就算安装完成。

    npm install -g node-gyp
    npm install --global --production windows-build-tools
    

    2.安装白垩主题

    可以从 npm 安装或者从 GitHub 拉取最新代码。

    # 从 npm
    npm i element-theme-chalk -D
    
    # 从 GitHub
    npm i https://github.com/ElementUI/theme-chalk -D
    

    3.新建颜色挑选组件

    注意:ORIGINAL_THEME 值不能改变,否则默认按钮颜色不会改变。

    代码如下:

    <template>
        <el-tooltip effect="dark" content="换肤" placement="bottom">
            <el-color-picker class="theme-picker" popper-class="theme-picker-dropdown" v-model="theme" :size="size"> </el-color-picker>
        </el-tooltip>
    </template>
    
    <script>
    const version = require('element-ui/package.json').version // element-ui version from node_modules
    const ORIGINAL_THEME = '#409EFF' // default color
    
    export default {
        name: 'ThemePicker',
        props: {
            default: {
                // 初始化主题,可由外部传入
                type: String,
                default: null,
            },
            size: {
                // 初始化主题,可由外部传入
                type: String,
                default: 'small',
            },
        },
        data() {
            return {
                chalk: '', // content of theme-chalk css
                theme: ORIGINAL_THEME,
                showSuccess: true, // 是否弹出换肤成功消息
            }
        },
        mounted() {
            if (this.default != null) {
                this.theme = this.default
                this.$emit('onThemeChange', this.theme)
                this.showSuccess = false
            }
        },
        watch: {
            theme(val, oldVal) {
                if (typeof val !== 'string') return
                const themeCluster = this.getThemeCluster(val.replace('#', ''))
                const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
                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
                    }
                }
    
                const chalkHandler = getHandler('chalk', 'chalk-style')
    
                if (!this.chalk) {
                    const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
                    this.getCSSString(url, chalkHandler, 'chalk')
                } else {
                    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 (typeof innerText !== 'string') return
                    style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
                })
    
                // 响应外部操作
                this.$emit('onThemeChange', val)
                if (this.showSuccess) {
                    this.$message({
                        message: '换肤成功',
                        type: 'success',
                    })
                } else {
                    this.showSuccess = true
                }
            },
        },
        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, callback, variable) {
                const xhr = new XMLHttpRequest()
                xhr.onreadystatechange = () => {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
                        callback()
                    }
                }
                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-picker .el-color-picker__trigger {
        vertical-align: middle;
    }
    
    .theme-picker-dropdown .el-color-dropdown__link-btn {
        display: none;
    }
    </style>
    

    然后在 vuex 对应 vue 模块中,添加颜色管理的状态值。

    在 头部添加 颜色选择的组件,供全局选择,代码如下:

    import ThemePicker from '@/components/ThemePicker'
    //引入组件
    components: { ThemePicker },
    
    //使用
    <theme-picker
    :default="themeColor"
    @onThemeChange="onThemeChange">
    </theme-picker>
    
    
    methods: {
         // 切换主题方法
         onThemeChange (themeColor)
        {
             this.$store.commit("setThemeColor", themeColor);
        }
    } //将颜色用状态管理器管理。
    

    在每次颜色改变时,设置到 state.themeColor 上,在各个需要改变皮肤的地方,从 state 中取出来,然后赋值进去。

    原文地址:http://book.levy.net.cn/doc/frontend/uiframe/custom_theme.html

  • 相关阅读:
    Code Forces Gym 100886J Sockets(二分)
    CSU 1092 Barricade
    CodeChef Mahesh and his lost array
    CodeChef Gcd Queries
    CodeChef GCD2
    CodeChef Sereja and LCM(矩阵快速幂)
    CodeChef Sereja and GCD
    CodeChef Little Elephant and Balance
    CodeChef Count Substrings
    hdu 4001 To Miss Our Children Time( sort + DP )
  • 原文地址:https://www.cnblogs.com/levywang/p/13543743.html
Copyright © 2020-2023  润新知