• vue 实现自定义主题切换+日夜切换


    不多废话,直入主题 。文末会附上git代码链接

    自定义主题切换

    概述

    一般主题切换为两种需求:主题色切换/日夜切换。

    主题色切换:(基于elementUI

    在这里插入图片描述
    1、最开始想的是直接通过 el.style.setProperty(‘--el-color-primary’, colorValue)修改主题色变量,可以实现最基本的修改,但是修改后发现像elementUI主题色是会分为多个层级,比如鼠标移入会变得更亮等,并且在夜间模式 主题色也会有区别
    2、由1分析到需要用到css的mix()函数去将颜色混合成多个层级,然后如element这样--el-color-primary-light-xx设置覆盖。因为我需要动态设置所以需要通过JS调用mix()函数,但是发现在js中无法操作css的mix()函数。在网上也没有找到方法
    3、用js手动实现mix()函数的混合颜色分级算法,在网上看到了gradient算法,由此可以实现两种颜色混合分级
    如:亮色下 elementUI的主题色409eff#ffffff混合分10级后就刚好是对应的--el-color-primary-light- 1~9
    算法如下:

    function gradientColor(this: any, startColor: any, endColor: any, step: any) {
        let startRGB = gradientColor.prototype.colorRgb(startColor);//转换为rgb数组模式
        let startR = startRGB[0];
        let startG = startRGB[1];
        let startB = startRGB[2];
        let endRGB = gradientColor.prototype.colorRgb(endColor);
        let endR = endRGB[0];
        let endG = endRGB[1];
        let endB = endRGB[2];
        let sR = (endR - startR) / step;//总差值
        let sG = (endG - startG) / step;
        let sB = (endB - startB) / step;
        var colorArr = [];
        for (var i = 0; i < step; i++) {
            //计算每一步的hex值 
            var hex = gradientColor.prototype.colorHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')');
            colorArr.push(hex);
        }
        return colorArr;
    }
    // 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
    gradientColor.prototype.colorRgb = function (sColor: any) {
        var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
        var sColor = sColor.toLowerCase();
        if (sColor && reg.test(sColor)) {
            if (sColor.length === 4) {
                var sColorNew = "#";
                for (var i = 1; i < 4; i += 1) {
                    sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
                }
                sColor = sColorNew;
            }
            //处理六位的颜色值
            var sColorChange = [];
            for (var i = 1; i < 7; i += 2) {
                sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
            }
            return sColorChange;
        } else {
            return sColor;
        }
    };
    // 将rgb表示方式转换为hex表示方式
    gradientColor.prototype.colorHex = function (rgb: any) {
        var _this = rgb;
        var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
        if (/^(rgb|RGB)/.test(_this)) {
            var aColor = _this.replace(/(?:(|)|rgb|RGB)*/g, "").split(",");
            var strHex = "#";
            for (var i = 0; i < aColor.length; i++) {
                var hex: any = Number(Number(aColor[i]).toString(16));
                hex = hex < 10 ? 0 + '' + hex : hex;// 保证每个rgb的值为2位
                if (hex === "0") {
                    hex += hex;
                }
                strHex += hex;
            }
            if (strHex.length !== 7) {
                strHex = _this;
            }
            return strHex;
        } else if (reg.test(_this)) {
            var aNum = _this.replace(/#/, "").split("");
            if (aNum.length === 6) {
                return _this;
            } else if (aNum.length === 3) {
                var numHex = "#";
                for (var i = 0; i < aNum.length; i += 1) {
                    numHex += (aNum[i] + aNum[i]);
                }
                return numHex;
            }
        } else {
            return _this;
        }
    }
    export default { gradientColor }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 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
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    4、实现色彩分级后就简单了,按照elementUI的色彩层级依次覆盖

    //设置主题色
    const setTheme = (colorName: string, color: string): void => {
        const el = document.documentElement
        const oldColor = getComputedStyle(el).getPropertyValue(`--c-base`).trim()
        let gradient: any = getColorArr.gradientColor(color, oldColor, 10);
        gradient.forEach((item: string, index: number) => {
            if (index === 0) el.style.setProperty(`${colorName}`, item)
            if (index === 9) return
            el.style.setProperty(`${colorName}-light-${index + 1}`, item)
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5、完全自定义修改主题色就成功啦,需要注意的是如果网站有日夜主题切换功能,日间模式是用白色和主题色混合分为十级,而夜间模式是用黑色和主题色混合分十级

    日夜切换

    主题色切换只用改变主题的颜色 背景之类的无需改变,但是日夜切换要将所有的色调取反,用上面的方法就很显笨拙了
    1、默认用了element-plus (如果没用按照下面步骤也完全可以实现),elementUI的包里内置的就有一套夜间模式css, 需要再main.ts中引用import 'element-plus/theme-chalk/dark/css-vars.css',element-plus文档描述直接在html标签上加一个class='dark'就可以实现了

    2、网站上没有用到element-plus的元素用第一步的设置是无法实现的,因此需要自己手动定义css变量并修改

    //定义css变量
    :root {
        --c-base: #ffffff;
        --c-text-common: #303133;
        --c-text-regular: #606266;
        --c-text-disabled: #C0C4CC;
    
        --c-menu-text: white;
        --el-color-primary: aqua;
    
        --c-bg-body: #E6E8EB;
        --c-bg-box: white;
    
        --c-bg-header:rgba(255,255,255,.5);
    
        --c-border: #CDD0D6;
    
        --c-shadow: rgba(0, 0, 0, 0.5);
    }
    
    :root[theme='dark'] {
        --c-base: #000000;
        --c-text-common: #E5EAF3;
        --c-text-regular: #A3A6AD;
        --c-text-disabled: #6C6E72;
    
        --c-menu-text: white;
        --el-color-primary: #409eff;
    
        --c-bg-body: #292a2d;
        --c-bg-box: #424243;
    
        --c-bg-header:rgba(0,0,0,.5);
    
    
        --c-border: #636466;
    
        --c-shadow: rgba(255, 255, 255, 0.5);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3、在页面上使用就不要再直接给定颜色了,而是用变量表示

     //base.css
     color: var(--color-text);
     background: var(--color-background);
     transition: color 0.5s, background-color 0.5s;
    
    • 1
    • 2
    • 3
    • 4

    4、主题切换操作

    const change_moon_sun = (): void => {
        ifSun = !ifSun
        if (ifSun) {
            utils.setStyle('.switch-moon-sun', 'left', '0px')//日月切换动画
            document.documentElement.removeAttribute('theme') //原生dom色彩改变
            document.documentElement.classList.remove('dark')//elementUi改变
            utils.setTheme('--el-color-primary', localStorage.getItem('--el-color-primary') || '#409eff')//改变主题渐变色
        }
        else {
            utils.setStyle('.switch-moon-sun', 'left', '-' + domWidth)
            document.documentElement.setAttribute('theme', 'dark')
            document.documentElement.classList.add('dark')
            utils.setTheme('--el-color-primary', localStorage.getItem('--el-color-primary') || '#409eff')
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    后言

    这个主题切换是我在搭建个人主页时用到的一个功能,用的vue3+ts+element-plus,但是文中的修改主题方法其实与框架无关,主要是css变量和dom操作

    个人demo的git链接

  • 相关阅读:
    基于VB6的颜色取色器 - 开源研究系列文章 - 个人小作品
    UACANet: Uncertainty Augmented Context Attention for Polyp Segmentation
    全自动测试-2-测试页面添加搜索
    数据库之MVCC
    ⑦、企业快速开发平台Spring Cloud之HTML 图像
    优化器Optimal
    c#旋转图片并保存在本地
    14.梯度检测、随机初始化、神经网络总结
    MES解决方案赋能「汽车改装行业」
    Docker 镜像拉取
  • 原文地址:https://blog.csdn.net/qq_43223007/article/details/127520694