当前位置:   article > 正文

vue-cli3,vue2+elementui实现用户自定义主题色,切换主题,(2023-02-10增加功能:后台可配置主题色以及功能色)_vue2+element 主题切换方案

vue2+element 主题切换方案

自定义主题色包含以下两种,并且这两种的主题色需要同步

  1. element-ui的主题色
  2. 程序员自己写的样式中的主题色

我参考

  1. 一篇博客:vue,elementUI切换主题,自定义主题 - 小兔额乖乖 - 博客园
  2. 一个开源框架:腾讯的tDesign搭建的开源框架——TDesign Vue Next Starter

输出了此篇文章

说明1:小兔额乖乖文章中的项目示例,在修改主题色后,刷新一下,鼠标hover时会有问题,此问题在本篇文章中已经解决

说明2:我曾经尝试完全模仿腾讯那个框架的思路。但是此思路不适用于element-ui这个框架,会报错

说明3:下面的正文中,项目中修改主题色时,会运行  document.head.appendChild(style)  ,修改一次颜色就会添加一个stylesheet,有兴趣的同学可以优化一下,改成替换掉上一次的style。

 以下是正文

---------------------------------------------------------------------------------------------------------------------------------

1、创建一个vue项目

① vue-cli3创建项目 

vue create vue-custom-theme

② 安装element-ui相关

安装elementUI

npm i element-ui -S

安装sass  

npm install node-sass@4.11.0 sass-loader@7.1.0 -D

 启动项目

npm run serve

2、引入element-ui

①在main,js中

  1. import ElementUI from 'element-ui'
  2. import './styles.scss'
  3. Vue.use(ElementUI)

②给一个默认的主题色【此步骤可省略,不需要。因为可以在Theme.vue中直接从后台获取默认主题(this.$store.state.sysConfig.theme)。this.$store.state.sysConfig.theme是在后台获取的,存储在了vuex里面,获取时机是全局路由拦截,在进入页面之前获取的】

用户先从线上拉去配置主题的css文件,当用户更改颜色后,在把css文件里面所有的颜色值替换掉,然后把这个css文件重新插入到html中达到改变颜色。

在这里都需要修改再方法1的基础上进行扩展:在element-variables.scss(大部分项目都是)添加 默认我们自己设置的颜色。

当然这个颜色也可以在其他公共css修改。我是在style.scss中修改的,如下

style.scss

  1. /* theme color */
  2. $--color-primary: #ff6f4b;
  3. /* icon font path, required */
  4. $--font-path: '~element-ui/lib/theme-chalk/fonts';
  5. @import "~element-ui/packages/theme-chalk/src/index";

3、主题色修改

①安装两个插件

  1. npm install css-color-function
  2. npm install object-assign

③ 从 unpkg.com/element-ui/lib/theme-chalk/index.css 把最新css文件复制下来copy到项目静态文件目录中:

④  接下来就是写代码了。在App.vue上引入自定义的修改主题组件,再随便弄些element组件观察变化:

 ⑤写组件:Theme.vue

  1. <!-- 切换主题色 -->
  2. <template>
  3. <div class="handle-theme">
  4. <el-color-picker
  5. @change="colorChange"
  6. v-model="colors.primary"
  7. ></el-color-picker>
  8. </div>
  9. </template>
  10. <script>
  11. import generateColors from "@/utils/color";
  12. import objectAssign from 'object-assign';
  13. export default {
  14. name: 'App',
  15. data() {
  16. return {
  17. originalStylesheetCount: -1, // 记录当前已引入style数量
  18. originalStyle: '', // 获取拿到的.css的字符串
  19. colors: {
  20. primary: '#ff6f4b',// this.$store.state.sysConfig.theme,
  21. success: '#00c5bd',
  22. warning: '#f39800',
  23. danger: '#f56c6c',
  24. info: '#909399'
  25. },
  26. // primaryColor: "", //提交成功后设置默认颜色
  27. cssUrl: [
  28. '//unpkg.com/element-ui/lib/theme-chalk/index.css',
  29. process.env.BASE_URL + 'static/css/index.css'
  30. ]
  31. };
  32. },
  33. methods: {
  34. initTheme() {
  35. // 默认从线上官方拉取最新css,2秒钟后做一个检查没有拉到就从本地在拉下
  36. // 如果是记住用户的状态就需要,在主题切换的时候记录颜色值,在下次打开的时候从新赋值
  37. this.colors.primary = localStorage.getItem('color') || this.colors.primary; // 例如
  38. // this.getIndexStyle(this.cssUrl[0]);
  39. // setTimeout(() =>{
  40. // if (this.originalStyle) {
  41. // return;
  42. // } else {
  43. this.getIndexStyle(this.cssUrl[1]);
  44. // }
  45. // }, 2000);
  46. this.$nextTick(() => {
  47. // 获取页面一共引入了多少个style 文件
  48. this.originalStylesheetCount = document.styleSheets.length;
  49. });
  50. },
  51. colorChange(e) {
  52. if (!e) return;
  53. this.primaryColor = e;
  54. localStorage.setItem('color', e);
  55. let primarySeries = this.generateColors('p', e)
  56. let successSeries = this.generateColors('s', this.colors.success)
  57. let warningSeries = this.generateColors('w', this.colors.warning)
  58. let dangerSeries = this.generateColors('d', this.colors.danger)
  59. let infoSeries = this.generateColors('i', this.colors.info)
  60. this.colors = objectAssign(
  61. {},
  62. this.colors,
  63. primarySeries,
  64. successSeries,
  65. warningSeries,
  66. dangerSeries,
  67. infoSeries
  68. );
  69. this.writeNewStyle();
  70. },
  71. writeNewStyle() {
  72. let cssText = this.originalStyle;
  73. Object.keys(this.colors).forEach((key) => {
  74. cssText = cssText.replace(
  75. new RegExp('(:|\\s+)' + key, 'g'),
  76. '$1' + this.colors[key]
  77. );
  78. });
  79. const style = document.createElement('style');
  80. style.innerText = `
  81. :root{
  82. --primary-color: ${this.colors.primary};
  83. --primary-color-light-1:${this.colors['pl-1']};
  84. --primary-color-light-2:${this.colors['pl-2']};
  85. --primary-color-light-3:${this.colors['pl-3']};
  86. --primary-color-light-4:${this.colors['pl-4']};
  87. --primary-color-light-5:${this.colors['pl-5']};
  88. --primary-color-light-6:${this.colors['pl-6']};
  89. --primary-color-light-7:${this.colors['pl-7']};
  90. --primary-color-light-8:${this.colors['pl-8']};
  91. --primary-color-light-9:${this.colors['pl-9']};
  92. }${cssText}`;
  93. // ":root{--primary-color:" + this.colors.primary + "}" + cssText;
  94. document.head.appendChild(style);
  95. // if (this.originalStylesheetCount === document.styleSheets.length) {
  96. // // 如果之前没有插入就插入
  97. // const style = document.createElement("style");
  98. // style.innerText =
  99. // ":root{--primary-color:" + this.colors.primary + "}" + cssText;
  100. // document.head.appendChild(style);
  101. // } else {
  102. // // 如果之前没有插入就修改
  103. // document.head.lastChild.innerText =
  104. // ":root{--primary-color:" +
  105. // this.colors.primary +
  106. // "} " +
  107. // cssText;
  108. // }
  109. },
  110. getIndexStyle(url) {
  111. var request = new XMLHttpRequest();
  112. request.open('GET', url);
  113. request.onreadystatechange = () => {
  114. if (
  115. request.readyState === 4 &&
  116. (request.status == 200 || request.status == 304)
  117. ) {
  118. // 调用本地的如果拿不到会得到html,html是不行的
  119. if (request.response && !/DOCTYPE/gi.test(request.response)) {
  120. this.originalStyle = this.getStyleTemplate(request.response);
  121. this.colorChange(this.colors.primary);
  122. } else {
  123. this.originalStyle = '';
  124. }
  125. } else {
  126. this.originalStyle = '';
  127. }
  128. };
  129. request.send(null);
  130. },
  131. getStyleTemplate(data) {
  132. const colorMap = {
  133. // "#3a8ee6": "shade-1",
  134. // "#409eff": "primary",
  135. // "#53a8ff": "light-1",
  136. // "#66b1ff": "light-2",
  137. // "#79bbff": "light-3",
  138. // "#8cc5ff": "light-4",
  139. // "#a0cfff": "light-5",
  140. // "#b3d8ff": "light-6",
  141. // "#c6e2ff": "light-7",
  142. // "#d9ecff": "light-8",
  143. // "#ecf5ff": "light-9",
  144. '#3a8ee6': 'ps-1',
  145. '#409eff': 'primary',
  146. '#53a8ff': 'pl-1',
  147. '#66b1ff': 'pl-2',
  148. '#79bbff': 'pl-3',
  149. '#8cc5ff': 'pl-4',
  150. '#a0cfff': 'pl-5',
  151. '#b3d8ff': 'pl-6',
  152. '#c6e2ff': 'pl-7',
  153. '#d9ecff': 'pl-8',
  154. '#ecf5ff': 'pl-9',
  155. '#5daf34': 'ss-1', // is-plain:active
  156. '#67c23a': 'success', // success
  157. '#76c84e': 'sl-1', // 没有
  158. '#85ce61': 'sl-2', // hover color
  159. '#95d475': 'sl-3', // 没有
  160. '#a4da89': 'sl-4', // is-disabled hover color
  161. '#b3e19d': 'sl-5', // is-disabled color
  162. '#c2e7b0': 'sl-6', // border-color
  163. '#d1edc4': 'sl-7', // 没有
  164. '#e1f3d8': 'sl-8', // light
  165. '#f0f9eb': 'sl-9', // lighter
  166. '#cf9236': 'ws-1', // is-plain:active
  167. '#E6A23C': 'warning', // success
  168. '#e9ab50': 'wl-1', // 没有
  169. '#ebb563': 'wl-2', // hover color
  170. '#eebe77': 'wl-3', // 没有
  171. '#f0c78a': 'wl-4', // is-disabled hover color
  172. '#f3d19e': 'wl-5', // is-disabled color
  173. '#f5dab1': 'wl-6', // border-color
  174. '#f8e3c5': 'wl-7', // 没有
  175. '#faecd8': 'wl-8', // light
  176. '#fdf6ec': 'wl-9', // lighter
  177. '#dd6161': 'ds-1', // is-plain:active
  178. '#F56C6C': 'danger', // success
  179. '#f67b7b': 'dl-1', // 没有
  180. '#f78989': 'dl-2', // hover color
  181. '#f89898': 'dl-3', // 没有
  182. '#f9a7a7': 'dl-4', // is-disabled hover color
  183. '#fab6b6': 'dl-5', // is-disabled color
  184. '#fbc4c4': 'dl-6', // border-color
  185. '#fcd3d3': 'dl-7', // 没有
  186. '#fde2e2': 'dl-8', // light
  187. '#fef0f0': 'dl-9', // lighter
  188. '#82848a': 'is-1', // is-plain:active
  189. '#909399': 'info', // success
  190. '#9b9ea3': 'il-1', // 没有
  191. '#a6a9ad': 'il-2', // hover color
  192. '#b1b3b8': 'il-3', // 没有
  193. '#bcbec2': 'il-4', // is-disabled hover color
  194. '#c8c9cc': 'il-5', // is-disabled color
  195. '#d3d4d6': 'il-6', // border-color
  196. '#dedfe0': 'il-7', // 没有
  197. '#e9e9eb': 'il-8', // light
  198. '#f4f4f5': 'il-9'// lighter
  199. };
  200. Object.keys(colorMap).forEach((key) => {
  201. const value = colorMap[key];
  202. data = data.replace(new RegExp(key, 'ig'), value);
  203. });
  204. return data;
  205. }
  206. },
  207. mounted() {
  208. this.initTheme();
  209. // 默认从线上官方拉取最新css,2秒钟后做一个检查没有拉到就从本地在拉下
  210. // let that = this;
  211. // 如果是记住用户的状态就需要,在主题切换的时候记录颜色值,在下次打开的时候从新赋值
  212. // this.colors.primary = localStorage.getItem('color')||this.colors.primary//例如
  213. // setTimeout(function() {
  214. // if (that.originalStyle) {
  215. // return;
  216. // } else {
  217. // that.getIndexStyle(that.cssUrl[1]);
  218. // }
  219. // }, 2000);
  220. // this.$nextTick(() => {
  221. // // 获取页面一共引入了多少个style 文件
  222. // this.originalStylesheetCount = document.styleSheets.length;
  223. // });
  224. }
  225. };
  226. </script>
  227. <style lang="scss">
  228. </style>

使用

  1. .boxDiv{
  2. padding:40px;
  3. background: var(--primary-color);
  4. box-shadow: 0 0 10px 8px var(--primary-color-light-8);
  5. }

 

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

闽ICP备14008679号