vue 实现自定义主题切换+日夜切换
自定义主题切换、日夜切换、一键换肤(无需加载多套css)案例+思路+代码
不多废话,直入主题 。文末会附上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 }
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)
})
}
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);
}
3、在页面上使用就不要再直接给定颜色了,而是用变量表示
//base.css
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
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')
}
}
后言
这个主题切换是我在搭建个人主页时用到的一个功能,用的vue3+ts+element-plus,但是文中的修改主题方法其实与框架无关,主要是css变量和dom操作
更多推荐
所有评论(0)