element如何动态切换主题(vite+vue+ts+elementPlus)
提示动态切换主题使用的是css3的var函数现实示例切换--main-bg-color的值,使用那么当前标签下的所有节点使用到当前变量的都会发生变化root{coral;}#div1{}#div2{}查看element.sass源码可以发现,一个primary样式,可以生成多个渐变色$types}}}不难发现/***/namespacestring;/**......
·
前言
提示:动态切换主题使用的是css3的var函数现实
示例:切换--main-bg-color的值,使用<div style="--main-bg-color:red"> </div> 那么当前标签下的所有节点使用到当前变量的都会发生变化
:root {
--main-bg-color: coral;
}
#div1 {
background-color: var(--main-bg-color);
}
#div2 {
background-color: var(--main-bg-color);
}
一、elementui css变量都有哪些
通过浏览器检查,发现element ui库的变量
二、如何修改这些变量
提示: 众所周知css是从上往下执行,如果我们可以在hand标签里最后一个添加一个style标签,是不是就可以重写掉element ui的变量
1.添加在head标签里面添加style标签(在main.ts添加如下代码)
代码如下(示例):
代码如下:
const style = document.createElement("style");
style.innerText = ":root{--el-color-primary:red}";
document.head.appendChild(style);
可以发现elementui的主色调已经被我们替换为红色
三、如何动态修改颜色
前言:
- 查看element.sass源码可以发现,一个primary样式,可以生成多个渐变色
$types: primary, success, warning, danger, error, info; @each $type in $types { @for $i from 1 through 9 { @include set-color-mix-level($type, $i, 'light', $color-white); } } // --el-color-primary-dark-2 @each $type in $types { @include set-color-mix-level($type, 2, 'dark', $color-black); }
不难发现 --el-color-primary-dark-2变量 是当前primary颜色跟黑色混和百分之20生成的颜色
所以设置一个primary的颜色会生成会生成1-9的和白色混的渐变色,生产一个百分之20的和黑色混的颜色
那么我们的变量就分为俩种:
推断类型: 通过一个主色调变量,生成n个渐变色
键值类型:一个变量对应一个值
直接上代码
定义数据类型
interface ThemeSetting {
/**
*element-ui Namespace
*/
namespace: string;
/**
* 数据分隔符
*/
division: string;
/**
* 前缀
*/
startDivision: string;
/**
* 颜色外推设置
*/
colorInferSetting: ColorInferSetting;
}
/**
* 颜色混和设置
*/
interface ColorInferSetting {
/**
* 与白色混
*/
light: Array<number>;
/**
* 与黑色混
*/
dark: Array<number>;
/**
* 类型
*/
type: string;
}
/**
* 平滑数据
*/
interface KeyValueData {
[propName: string]: string;
}
type UpdateInferData = KeyValueData;
type UpdateKeyValueData = KeyValueData;
/**
*平滑数据
*/
interface InferData {
/**
* 设置
*/
setting?: ColorInferSetting | any;
/**
* 健
*/
key: string;
/**
* 值
*/
value: string;
}
export type {
KeyValueData,
InferData,
ThemeSetting,
UpdateInferData,
UpdateKeyValueData,
};
定义配置数据
import type { ThemeSetting } from "./type";
const setting: ThemeSetting = {
namespace: "el",
division: "-",
startDivision: "--",
colorInferSetting: {
light: [3, 5, 7, 8, 9],
dark: [2],
type: "color",
},
};
export default setting;
定义默认推断数据
import type { InferData } from "./type";
const inferDatas: Array<InferData> = [];
export default inferDatas;
定义默认键值数据
import type { KeyValueData } from "./type";
const keyValueData: KeyValueData = {
"menu-item-height": "56px",
};
export default keyValueData;
编写动态修改主题代码
import type {
ThemeSetting,
InferData,
KeyValueData,
UpdateInferData,
UpdateKeyValueData,
} from "./type";
import tinycolor from "@ctrl/tinycolor";
declare global {
interface ChildNode {
innerText: string;
}
}
class Theme {
/**
* 主题设置
*/
themeSetting: ThemeSetting;
/**
* 键值数据
*/
keyValue: KeyValueData;
/**
* 外推数据
*/
inferDatas: Array<InferData>;
/**
*是否是第一次初始化
*/
isFirstWriteStyle: boolean;
/**
* 混色白
*/
colorWhite: string;
/**
* 混色黑
*/
colorBlack: string;
constructor(
themeSetting: ThemeSetting,
keyValue: KeyValueData,
inferDatas: Array<InferData>
) {
this.themeSetting = themeSetting;
this.keyValue = keyValue;
this.inferDatas = inferDatas;
this.isFirstWriteStyle = true;
this.colorWhite = "#ffffff";
this.colorBlack = "#000000";
}
/**
* 拼接
* @param setting 主题设置
* @param names 需要拼接的所有值
* @returns 拼接后的数据
*/
getVarName = (setting: ThemeSetting, ...names: Array<string>) => {
return (
setting.startDivision +
setting.namespace +
setting.division +
names.join(setting.division)
);
};
/**
* 转换外推数据
* @param setting 主题设置对象
* @param inferData 外推数据
* @returns
*/
mapInferMainStyle = (setting: ThemeSetting, inferData: InferData) => {
const key: string = this.getVarName(
setting,
inferData.setting
? inferData.setting.type
: setting.colorInferSetting.type,
inferData.key
);
return {
[key]: inferData.value,
...this.mapInferDataStyle(setting, inferData),
};
};
/**
* 转换外推数据
* @param setting 设置
* @param inferDatas 外推数据
*/
mapInferData = (setting: ThemeSetting, inferDatas: Array<InferData>) => {
return inferDatas
.map((itemData) => {
return this.mapInferMainStyle(setting, itemData);
})
.reduce((pre, next) => {
return { ...pre, ...next };
}, {});
};
/**
* 转换外推数据
* @param setting 主题设置对象
* @param inferData 外推数据
* @returns
*/
mapInferDataStyle = (setting: ThemeSetting, inferData: InferData) => {
const inferSetting = inferData.setting
? inferData.setting
: setting.colorInferSetting;
if (inferSetting.type === "color") {
return Object.keys(inferSetting)
.map((key: string) => {
if (key === "light" || key === "dark") {
return inferSetting[key]
.map((l) => {
const varName = this.getVarName(
setting,
inferSetting.type,
inferData.key,
key,
l.toString()
);
return {
[varName]: tinycolor(inferData.value)
.mix(
key === "light" ? this.colorWhite : this.colorBlack,
l * 10
)
.toHexString(),
};
})
.reduce((pre, next) => {
return { ...pre, ...next };
}, {});
}
return {};
})
.reduce((pre, next) => {
return { ...pre, ...next };
}, {});
}
return {};
};
/**
*
* @param themeSetting 主题设置
* @param keyValueData 键值数据
* @returns 映射后的键值数据
*/
mapKeyValue = (themeSetting: ThemeSetting, keyValueData: KeyValueData) => {
return Object.keys(keyValueData)
.map((key: string) => {
return {
[this.updateKeyBySetting(key, themeSetting)]: keyValueData[key],
};
})
.reduce((pre, next) => {
return { ...pre, ...next };
}, {});
};
/**
* 根据配置文件修改Key
* @param key key
* @param themeSetting 主题设置
* @returns
*/
updateKeyBySetting = (key: string, themeSetting: ThemeSetting) => {
return key.startsWith(themeSetting.startDivision)
? key
: key.startsWith(themeSetting.namespace)
? themeSetting.startDivision + key
: key.startsWith(themeSetting.division)
? themeSetting.startDivision + themeSetting.namespace
: themeSetting.startDivision +
themeSetting.namespace +
themeSetting.division +
key;
};
/**
*
* @param setting 主题设置
* @param keyValue 主题键值对数据
* @param inferDatas 外推数据
* @returns 合并后的键值对数据
*/
tokeyValueStyle = () => {
return {
...this.mapInferData(this.themeSetting, this.inferDatas),
...this.mapKeyValue(this.themeSetting, this.keyValue),
};
};
/**
* 将keyValue对象转换为S
* @param keyValue
* @returns
*/
toString = (keyValue: KeyValueData) => {
const inner = Object.keys(keyValue)
.map((key: string) => {
return key + ":" + keyValue[key] + ";";
})
.join("");
return `@charset "UTF-8";:root{${inner}}`;
};
/**
*
* @param elNewStyle 新的变量样式
*/
writeNewStyle = (elNewStyle: string) => {
if (this.isFirstWriteStyle) {
const style = document.createElement("style");
style.innerText = elNewStyle;
document.head.appendChild(style);
this.isFirstWriteStyle = false;
} else {
if (document.head.lastChild) {
document.head.lastChild.innerText = elNewStyle;
}
}
};
/**
* 修改数据并且写入dom
* @param updateInferData 平滑数据修改
* @param updateKeyvalueData keyValue数据修改
*/
updateWrite = (
updateInferData?: UpdateInferData,
updateKeyvalueData?: UpdateKeyValueData
) => {
this.update(updateInferData, updateKeyvalueData);
const newStyle = this.tokeyValueStyle();
const newStyleString = this.toString(newStyle);
this.writeNewStyle(newStyleString);
};
/**
* 修改数据
* @param inferData
* @param keyvalueData
*/
update = (
updateInferData?: UpdateInferData,
updateKeyvalueData?: UpdateKeyValueData
) => {
if (updateInferData) {
this.updateInferData(updateInferData);
}
if (updateKeyvalueData) {
this.updateOrCreateKeyValueData(updateKeyvalueData);
}
};
/**
* 修改外推数据 外推数据只能修改,不能新增
* @param inferData
*/
updateInferData = (updateInferData: UpdateInferData) => {
Object.keys(updateInferData).forEach((key) => {
const findInfer = this.inferDatas.find((itemInfer) => {
return itemInfer.key === key;
});
if (findInfer) {
findInfer.value = updateInferData[key];
} else {
this.inferDatas.push({ key, value: updateInferData[key] });
}
});
};
/**
* 修改KeyValue数据
* @param keyvalueData keyValue数据
*/
updateOrCreateKeyValueData = (updateKeyvalueData: UpdateKeyValueData) => {
Object.keys(updateKeyvalueData).forEach((key) => {
const newKey = this.updateKeyBySetting(key, this.themeSetting);
this.keyValue[newKey] = updateKeyvalueData[newKey];
});
};
}
export default Theme;
使用
// 引入主题对象
import Theme from "./theme";
// 引入默认推断数据
import inferDatas from "./theme/inferDatas";
// 引入默认keyValue数据
import keyValueData from "./theme/keyValueData";
// 引入设置对象
import setting from "./theme/setting";
const app = createApp(App);
// 创建主题对象
const theme = new Theme(setting, keyValueData, inferDatas);
// 将主题对象放到全局变量中
app.config.globalProperties.theme = theme;
其他组件使用
import { reactive, getCurrentInstance } from "vue";
import type { ComponentInternalInstance } from "vue";
const { appContext } = getCurrentInstance() as ComponentInternalInstance;
const theme = appContext.config.globalProperties.theme;
theme.updateWrite({ primary: form.themeColor });
API
- 修改推断数据
theme.updateWrite({
primary: "#409eff",
success: "#67c23a",
warning: "#e6a23c",
danger: "#f56c6c",
error: "#f56c6c",
info: "#909399",
});
- 修改键值类型数据
theme.updateWrite(undefined, {
"--el-menu-active-color": "red",
"--el-menu-bg-color": "pink",
"--el-menu-item-height": "22px",
});
- 一起修改
theme.updateWrite(
{
primary: "#409eff",
success: "#67c23a",
warning: "#e6a23c",
danger: "#f56c6c",
error: "#f56c6c",
info: "#909399",
},
{
"--el-menu-active-color": "red",
"--el-menu-bg-color": "pink",
"--el-menu-item-height": "22px",
}
);
总结:
主题数据可以存储在数据库中,通过接口查询后调用函数修改即可完成动态主题
更多推荐
已为社区贡献1条内容
所有评论(0)