elementUI+vue动态切换主题

本文参考的是vue-element-admin里的主题切换,并加以补充了一些问题,要是有不完善的地方,希望大家能帮忙指出。

  1. 在components目录中创建创建:ThemePicker/index.vue

这边主要的功能是选择颜色块之后,将获取到的element中相对应的主题颜色,存放到style标签页之后,进行replace替换所选择的颜色。

<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>
const version = require('element-ui/package.json').version
const ORIGINAL_THEME = '#409EFF'
import { setThemeChalk, getThemeCluster, updateStyle, getTheme } from '@/utils/auth'

export default {
    data() {
        return {
            chalk: '',
            theme: getTheme() ?? ORIGINAL_THEME,
        }
    },
    watch: {
        async theme(val) {
            const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
            if (typeof val !== 'string') return
            const themeCluster = getThemeCluster(val.replace('#', ''))
            const originalCluster = getThemeCluster(oldVal.replace('#', ''))
            const $message = this.$message({
                message: '  正在切换主题',
                customClass: 'theme-message',
                type: 'success',
                duration: 0,
                iconClass: 'el-icon-loading',
            })

            const getHandler = (variable, id) => {
                return () => {
                    const originalCluster = getThemeCluster(ORIGINAL_THEME.replace('#', ''))
                    const newStyle = 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 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 (typeof innerText !== 'string') return
                style.innerText = updateStyle(innerText, originalCluster, themeCluster)
            })

            this.$emit('change', val, themeCluster)

            $message.close()
        },
    },

    methods: {
        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{[^}]+}/, '')
                        setThemeChalk(this[variable])
                        resolve()
                    }
                }
                xhr.open('GET', url)
                xhr.send()
            })
        },
    },
}
</script>

<style lang="scss">
.theme-message,
.theme-picker-dropdown {
    z-index: 99999 !important;
}

.theme-picker .el-color-picker__trigger {
    height: 26px !important;
    width: 26px !important;
    margin-top: 14px;
    padding: 2px;
}

.theme-picker-dropdown .el-color-dropdown__link-btn {
    display: none;
}
.el-color-picker__color-inner {
    background-color: $commonColor !important;
}
</style>
  1. 在utils目录中创建创建:auth.js

//主题颜色
export function setTheme (val) {
    return localStorage.setItem('theme_color', val)
}

export function getTheme () {
    return localStorage.getItem('theme_color')
}
//主题element文件
export function setThemeChalk (val) {
    return localStorage.setItem('theme_chalk', val)
}

export function getThemeChalk () {
    return localStorage.getItem('theme_chalk')
}

//获取相对应的颜色
export function 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
}

//更改替换主题颜色
export function updateStyle (style, oldCluster, newCluster) {
    let newStyle = style
    oldCluster.forEach((color, index) => {
        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
    })
    return newStyle
}
  1. 引用组件

<template>
    <!-- 主题切换 -->
    <theme-picker class="right-menu-item hover-effect" @change="themeChange"></theme-picker>
</template>
<script>
import ThemePicker from '@/components/ThemePicker'
import { setTheme } from '@/utils/auth'
export default {
    components: {
        ThemePicker,
    },
    methods: {
        themeChange(val, valJSON) {
            //这边的代码后面讲解
            document.getElementsByTagName('body')[0].style.setProperty('--common-color', val)
            document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-border-hover', valJSON[valJSON.length - 4])
            document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-bac-hover', valJSON[valJSON.length - 2])
            //将拿到的颜色存到localstorage里
            setTheme(val)
        },
    },
}
</script>

到这儿,element组件的主题切换就完成了。

那如果我们自己写的样式里的颜色应该怎么解决呢?

  1. 在styles目录中创建:variables.scss

:root {
    --common-color: #409eff;
    --defaultbutton-bac-hover: #ecf5ff;
    --defaultbutton-border-hover: #c6e2ff;
}

// 按钮公共颜色
$commonColor: var(--common-color);
$defaultbuttonBorderHover: var(--defaultbutton-border-hover);
$defaultbuttonBacHover: var(--defaultbutton-bac-hover);
在themeChange方法中,就要相对应的更改这边的变量
document.getElementsByTagName('body')[0].style.setProperty('--common-color', val)
document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-border-hover', valJSON[valJSON.length - 4])
document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-bac-hover', valJSON[valJSON.length - 2])

到这儿基础的主题切换已经完成了,但是会有个问题,那就是在我们页面去加载之后再去获取localstorage里的颜色并替换,会先出现原本颜色,然后再变成新颜色,有个一两秒的延迟。所以我们需要在App.vue文件中先初始化localstorage中的颜色。

<script>
import { getTheme, getThemeChalk, getThemeCluster, updateStyle } from '@/utils/auth'
const ORIGINAL_THEME = '#409EFF'
export default {
    name: 'App',
    beforeMount() {
        let default_theme = getTheme()
        if (default_theme) {
            let default_theme_chalk = getThemeChalk()
            const themeCluster = getThemeCluster(default_theme.replace('#', ''))
            const originalCluster = getThemeCluster(ORIGINAL_THEME.replace('#', ''))
            const newStyle = updateStyle(default_theme_chalk, originalCluster, themeCluster)
            let styleTag = document.getElementById('chalk-style')
            if (!styleTag) {
                let styleTag = document.createElement('style')
                styleTag.setAttribute('id', 'chalk-style')
                document.head.appendChild(styleTag)
            }
            document.getElementById('chalk-style').innerText = newStyle

            document.getElementsByTagName('body')[0].style.setProperty('--common-color', default_theme)
            document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-border-hover', themeCluster[themeCluster.length - 4])
            document.getElementsByTagName('body')[0].style.setProperty('--defaultbutton-bac-hover', themeCluster[themeCluster.length - 2])
        }
    },
}
</script>

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
VueElementUI都是非常流行的前端开发框架,它们可以让我们更加便捷地开发前端应用。其中,ElementUI提供了非常多的表单验证规则,可以让我们在表单输入时对用户的输入进行验证,增强了用户输入的可靠性和安全性。但是,有时候我们需要根据不同的表单输入,动态切换验证规则,以达到更加灵活的表单验证效果。那么,该如何实现动态切换验证规则呢? 首先,在Vue中我们可以通过v-if和v-else来切换不同的验证规则。例如: <template> <el-form ref="form" :model="formData" :rules="rules" label-width="100px"> <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name" placeholder="请输入姓名"></el-input> </el-form-item> <el-form-item label="年龄" prop="age"> <el-input v-model="formData.age" placeholder="请输入年龄"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('form')">提交</el-button> </el-form-item> </el-form> </template> <script> export default { data() { return { formData: { name: '', age: '' }, rules: { name: [ {required: true, message: '请输入姓名', trigger: 'blur'} ], age: [ {required: true, message: '请输入年龄', trigger: 'blur'} ] } } }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('提交成功') } else { alert('验证失败') return false } }) } } } </script> 在上面的代码中,我们定义了一个包含两个输入框(姓名和年龄)的表单,并根据不同的用户输入动态切换了验证规则。其中,rules是验证规则对象,包含了每个表单元素对应的验证规则。当我们需要根据输入内容动态切换规则时,只需要在对应的表单元素上设置v-if和v-else指令来切换不同的验证规则即可。 总之,在VueElementUI动态切换验证规则的原理就是利用Vue的特性动态切换v-if和v-else指令来实现,以满足不同的表单验证需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值