当前位置:   article > 正文

element如何动态切换主题(vite+vue+ts+elementPlus)_element plus 主题 :root

element plus 主题 :root


前言

提示:动态切换主题使用的是css3的var函数现实

示例:切换--main-bg-color的值,使用<div style="--main-bg-color:red"> </div> 那么当前标签下的所有节点使用到当前变量的都会发生变化

  1. :root {
  2. --main-bg-color: coral;
  3. }
  4. #div1 {
  5. background-color: var(--main-bg-color);
  6. }
  7. #div2 {
  8. background-color: var(--main-bg-color);
  9. }

一、elementui css变量都有哪些

 通过浏览器检查,发现element ui库的变量

二、如何修改这些变量

提示: 众所周知css是从上往下执行,如果我们可以在hand标签里最后一个添加一个style标签,是不是就可以重写掉element ui的变量

1.添加在head标签里面添加style标签(在main.ts添加如下代码)

代码如下(示例):

 

代码如下: 

  1. const style = document.createElement("style");
  2. style.innerText = ":root{--el-color-primary:red}";
  3. document.head.appendChild(style);

可以发现elementui的主色调已经被我们替换为红色

三、如何动态修改颜色

 前言: 

  1. 查看element.sass源码可以发现,一个primary样式,可以生成多个渐变色
    1. $types: primary, success, warning, danger, error, info;
    2. @each $type in $types {
    3. @for $i from 1 through 9 {
    4. @include set-color-mix-level($type, $i, 'light', $color-white);
    5. }
    6. }
    7. // --el-color-primary-dark-2
    8. @each $type in $types {
    9. @include set-color-mix-level($type, 2, 'dark', $color-black);
    10. }

不难发现 --el-color-primary-dark-2变量 是当前primary颜色跟黑色混和百分之20生成的颜色

所以设置一个primary的颜色会生成会生成1-9的和白色混的渐变色,生产一个百分之20的和黑色混的颜色

那么我们的变量就分为俩种:

  推断类型: 通过一个主色调变量,生成n个渐变色

  键值类型:一个变量对应一个值 

直接上代码

定义数据类型

  1. interface ThemeSetting {
  2. /**
  3. *element-ui Namespace
  4. */
  5. namespace: string;
  6. /**
  7. * 数据分隔符
  8. */
  9. division: string;
  10. /**
  11. * 前缀
  12. */
  13. startDivision: string;
  14. /**
  15. * 颜色外推设置
  16. */
  17. colorInferSetting: ColorInferSetting;
  18. }
  19. /**
  20. * 颜色混和设置
  21. */
  22. interface ColorInferSetting {
  23. /**
  24. * 与白色混
  25. */
  26. light: Array<number>;
  27. /**
  28. * 与黑色混
  29. */
  30. dark: Array<number>;
  31. /**
  32. * 类型
  33. */
  34. type: string;
  35. }
  36. /**
  37. * 平滑数据
  38. */
  39. interface KeyValueData {
  40. [propName: string]: string;
  41. }
  42. type UpdateInferData = KeyValueData;
  43. type UpdateKeyValueData = KeyValueData;
  44. /**
  45. *平滑数据
  46. */
  47. interface InferData {
  48. /**
  49. * 设置
  50. */
  51. setting?: ColorInferSetting | any;
  52. /**
  53. * 健
  54. */
  55. key: string;
  56. /**
  57. * 值
  58. */
  59. value: string;
  60. }
  61. export type {
  62. KeyValueData,
  63. InferData,
  64. ThemeSetting,
  65. UpdateInferData,
  66. UpdateKeyValueData,
  67. };

定义配置数据

  1. import type { ThemeSetting } from "./type";
  2. const setting: ThemeSetting = {
  3. namespace: "el",
  4. division: "-",
  5. startDivision: "--",
  6. colorInferSetting: {
  7. light: [3, 5, 7, 8, 9],
  8. dark: [2],
  9. type: "color",
  10. },
  11. };
  12. export default setting;

定义默认推断数据

  1. import type { InferData } from "./type";
  2. const inferDatas: Array<InferData> = [];
  3. export default inferDatas;

定义默认键值数据

  1. import type { KeyValueData } from "./type";
  2. const keyValueData: KeyValueData = {
  3. "menu-item-height": "56px",
  4. };
  5. export default keyValueData;

编写动态修改主题代码

  1. import type {
  2. ThemeSetting,
  3. InferData,
  4. KeyValueData,
  5. UpdateInferData,
  6. UpdateKeyValueData,
  7. } from "./type";
  8. import tinycolor from "@ctrl/tinycolor";
  9. declare global {
  10. interface ChildNode {
  11. innerText: string;
  12. }
  13. }
  14. class Theme {
  15. /**
  16. * 主题设置
  17. */
  18. themeSetting: ThemeSetting;
  19. /**
  20. * 键值数据
  21. */
  22. keyValue: KeyValueData;
  23. /**
  24. * 外推数据
  25. */
  26. inferDatas: Array<InferData>;
  27. /**
  28. *是否是第一次初始化
  29. */
  30. isFirstWriteStyle: boolean;
  31. /**
  32. * 混色白
  33. */
  34. colorWhite: string;
  35. /**
  36. * 混色黑
  37. */
  38. colorBlack: string;
  39. constructor(
  40. themeSetting: ThemeSetting,
  41. keyValue: KeyValueData,
  42. inferDatas: Array<InferData>
  43. ) {
  44. this.themeSetting = themeSetting;
  45. this.keyValue = keyValue;
  46. this.inferDatas = inferDatas;
  47. this.isFirstWriteStyle = true;
  48. this.colorWhite = "#ffffff";
  49. this.colorBlack = "#000000";
  50. }
  51. /**
  52. * 拼接
  53. * @param setting 主题设置
  54. * @param names 需要拼接的所有值
  55. * @returns 拼接后的数据
  56. */
  57. getVarName = (setting: ThemeSetting, ...names: Array<string>) => {
  58. return (
  59. setting.startDivision +
  60. setting.namespace +
  61. setting.division +
  62. names.join(setting.division)
  63. );
  64. };
  65. /**
  66. * 转换外推数据
  67. * @param setting 主题设置对象
  68. * @param inferData 外推数据
  69. * @returns
  70. */
  71. mapInferMainStyle = (setting: ThemeSetting, inferData: InferData) => {
  72. const key: string = this.getVarName(
  73. setting,
  74. inferData.setting
  75. ? inferData.setting.type
  76. : setting.colorInferSetting.type,
  77. inferData.key
  78. );
  79. return {
  80. [key]: inferData.value,
  81. ...this.mapInferDataStyle(setting, inferData),
  82. };
  83. };
  84. /**
  85. * 转换外推数据
  86. * @param setting 设置
  87. * @param inferDatas 外推数据
  88. */
  89. mapInferData = (setting: ThemeSetting, inferDatas: Array<InferData>) => {
  90. return inferDatas
  91. .map((itemData) => {
  92. return this.mapInferMainStyle(setting, itemData);
  93. })
  94. .reduce((pre, next) => {
  95. return { ...pre, ...next };
  96. }, {});
  97. };
  98. /**
  99. * 转换外推数据
  100. * @param setting 主题设置对象
  101. * @param inferData 外推数据
  102. * @returns
  103. */
  104. mapInferDataStyle = (setting: ThemeSetting, inferData: InferData) => {
  105. const inferSetting = inferData.setting
  106. ? inferData.setting
  107. : setting.colorInferSetting;
  108. if (inferSetting.type === "color") {
  109. return Object.keys(inferSetting)
  110. .map((key: string) => {
  111. if (key === "light" || key === "dark") {
  112. return inferSetting[key]
  113. .map((l) => {
  114. const varName = this.getVarName(
  115. setting,
  116. inferSetting.type,
  117. inferData.key,
  118. key,
  119. l.toString()
  120. );
  121. return {
  122. [varName]: tinycolor(inferData.value)
  123. .mix(
  124. key === "light" ? this.colorWhite : this.colorBlack,
  125. l * 10
  126. )
  127. .toHexString(),
  128. };
  129. })
  130. .reduce((pre, next) => {
  131. return { ...pre, ...next };
  132. }, {});
  133. }
  134. return {};
  135. })
  136. .reduce((pre, next) => {
  137. return { ...pre, ...next };
  138. }, {});
  139. }
  140. return {};
  141. };
  142. /**
  143. *
  144. * @param themeSetting 主题设置
  145. * @param keyValueData 键值数据
  146. * @returns 映射后的键值数据
  147. */
  148. mapKeyValue = (themeSetting: ThemeSetting, keyValueData: KeyValueData) => {
  149. return Object.keys(keyValueData)
  150. .map((key: string) => {
  151. return {
  152. [this.updateKeyBySetting(key, themeSetting)]: keyValueData[key],
  153. };
  154. })
  155. .reduce((pre, next) => {
  156. return { ...pre, ...next };
  157. }, {});
  158. };
  159. /**
  160. * 根据配置文件修改Key
  161. * @param key key
  162. * @param themeSetting 主题设置
  163. * @returns
  164. */
  165. updateKeyBySetting = (key: string, themeSetting: ThemeSetting) => {
  166. return key.startsWith(themeSetting.startDivision)
  167. ? key
  168. : key.startsWith(themeSetting.namespace)
  169. ? themeSetting.startDivision + key
  170. : key.startsWith(themeSetting.division)
  171. ? themeSetting.startDivision + themeSetting.namespace
  172. : themeSetting.startDivision +
  173. themeSetting.namespace +
  174. themeSetting.division +
  175. key;
  176. };
  177. /**
  178. *
  179. * @param setting 主题设置
  180. * @param keyValue 主题键值对数据
  181. * @param inferDatas 外推数据
  182. * @returns 合并后的键值对数据
  183. */
  184. tokeyValueStyle = () => {
  185. return {
  186. ...this.mapInferData(this.themeSetting, this.inferDatas),
  187. ...this.mapKeyValue(this.themeSetting, this.keyValue),
  188. };
  189. };
  190. /**
  191. * 将keyValue对象转换为S
  192. * @param keyValue
  193. * @returns
  194. */
  195. toString = (keyValue: KeyValueData) => {
  196. const inner = Object.keys(keyValue)
  197. .map((key: string) => {
  198. return key + ":" + keyValue[key] + ";";
  199. })
  200. .join("");
  201. return `@charset "UTF-8";:root{${inner}}`;
  202. };
  203. /**
  204. *
  205. * @param elNewStyle 新的变量样式
  206. */
  207. writeNewStyle = (elNewStyle: string) => {
  208. if (this.isFirstWriteStyle) {
  209. const style = document.createElement("style");
  210. style.innerText = elNewStyle;
  211. document.head.appendChild(style);
  212. this.isFirstWriteStyle = false;
  213. } else {
  214. if (document.head.lastChild) {
  215. document.head.lastChild.innerText = elNewStyle;
  216. }
  217. }
  218. };
  219. /**
  220. * 修改数据并且写入dom
  221. * @param updateInferData 平滑数据修改
  222. * @param updateKeyvalueData keyValue数据修改
  223. */
  224. updateWrite = (
  225. updateInferData?: UpdateInferData,
  226. updateKeyvalueData?: UpdateKeyValueData
  227. ) => {
  228. this.update(updateInferData, updateKeyvalueData);
  229. const newStyle = this.tokeyValueStyle();
  230. const newStyleString = this.toString(newStyle);
  231. this.writeNewStyle(newStyleString);
  232. };
  233. /**
  234. * 修改数据
  235. * @param inferData
  236. * @param keyvalueData
  237. */
  238. update = (
  239. updateInferData?: UpdateInferData,
  240. updateKeyvalueData?: UpdateKeyValueData
  241. ) => {
  242. if (updateInferData) {
  243. this.updateInferData(updateInferData);
  244. }
  245. if (updateKeyvalueData) {
  246. this.updateOrCreateKeyValueData(updateKeyvalueData);
  247. }
  248. };
  249. /**
  250. * 修改外推数据 外推数据只能修改,不能新增
  251. * @param inferData
  252. */
  253. updateInferData = (updateInferData: UpdateInferData) => {
  254. Object.keys(updateInferData).forEach((key) => {
  255. const findInfer = this.inferDatas.find((itemInfer) => {
  256. return itemInfer.key === key;
  257. });
  258. if (findInfer) {
  259. findInfer.value = updateInferData[key];
  260. } else {
  261. this.inferDatas.push({ key, value: updateInferData[key] });
  262. }
  263. });
  264. };
  265. /**
  266. * 修改KeyValue数据
  267. * @param keyvalueData keyValue数据
  268. */
  269. updateOrCreateKeyValueData = (updateKeyvalueData: UpdateKeyValueData) => {
  270. Object.keys(updateKeyvalueData).forEach((key) => {
  271. const newKey = this.updateKeyBySetting(key, this.themeSetting);
  272. this.keyValue[newKey] = updateKeyvalueData[newKey];
  273. });
  274. };
  275. }
  276. export default Theme;

使用

  1. // 引入主题对象
  2. import Theme from "./theme";
  3. // 引入默认推断数据
  4. import inferDatas from "./theme/inferDatas";
  5. // 引入默认keyValue数据
  6. import keyValueData from "./theme/keyValueData";
  7. // 引入设置对象
  8. import setting from "./theme/setting";
  9. const app = createApp(App);
  10. // 创建主题对象
  11. const theme = new Theme(setting, keyValueData, inferDatas);
  12. // 将主题对象放到全局变量中
  13. app.config.globalProperties.theme = theme;

其他组件使用

  1. import { reactive, getCurrentInstance } from "vue";
  2. import type { ComponentInternalInstance } from "vue";
  3. const { appContext } = getCurrentInstance() as ComponentInternalInstance;
  4. const theme = appContext.config.globalProperties.theme;
  5. theme.updateWrite({ primary: form.themeColor });

API

- 修改推断数据

  1. theme.updateWrite({
  2. primary: "#409eff",
  3. success: "#67c23a",
  4. warning: "#e6a23c",
  5. danger: "#f56c6c",
  6. error: "#f56c6c",
  7. info: "#909399",
  8. });

- 修改键值类型数据 

  1. theme.updateWrite(undefined, {
  2. "--el-menu-active-color": "red",
  3. "--el-menu-bg-color": "pink",
  4. "--el-menu-item-height": "22px",
  5. });

- 一起修改

  1. theme.updateWrite(
  2. {
  3. primary: "#409eff",
  4. success: "#67c23a",
  5. warning: "#e6a23c",
  6. danger: "#f56c6c",
  7. error: "#f56c6c",
  8. info: "#909399",
  9. },
  10. {
  11. "--el-menu-active-color": "red",
  12. "--el-menu-bg-color": "pink",
  13. "--el-menu-item-height": "22px",
  14. }
  15. );

总结:

  主题数据可以存储在数据库中,通过接口查询后调用函数修改即可完成动态主题

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/332427
推荐阅读
相关标签
  

闽ICP备14008679号