项目中安装插件

  1. npm i element-theme -D
  2. npm i element-theme-chalk -D
  3. "element-theme": "^2.0.1",
  4. "element-theme-chalk": "^2.15.6",

通过 node_modules/.bin/et 访问到命令。执行 -i 初始化变量文件。默认输出到 element-variables.scss,当然你可以传参数指定文件输出目录。

  1. node_modules/.bin/et -i

生成 element-variables.scss 文件

如果此时出现报错信息:primordials is not defined 解决方案: 使用的node版本更换为11.15.0

修改变量

直接编辑 element-variables.scss 文件,例如修改主题色为红色。

  1. $--color-primary: #d0021b !default;

编译主题

执行主题编译命令生成主题,根目录会生成一个theme的文件夹 。

  1. node_modules/.bin/et

image.png

引入自定义主题

把生成的主题按颜色改名放置 src/theme 目录下。
在 main.js 中import ‘所在路径/index.css’

  1. import Element from 'element-ui';
  2. // import 'element-ui/lib/theme-chalk/index.css'; // 默认的样式
  3. import "@/theme/index.css" // 自定义主题样式

👉动态换肤器方式

添加换肤组件

image.png
index.vue

  1. <template>
  2. <div class="ThemePick">
  3. <el-color-picker class="theme-picker" popper-class="theme-picker-dropdown" v-model="theme" :size="size">
  4. </el-color-picker>
  5. </div>
  6. </template>
  7. <script>
  8. const version = require('element-ui/package.json').version // element-ui version from node_modules
  9. const ORIGINAL_THEME = '#409EFF' // default color
  10. export default {
  11. name: 'ThemePick',
  12. props: {
  13. defaultTheme: {
  14. type: String,
  15. default: null
  16. },
  17. size: {
  18. type: String,
  19. default: 'small'
  20. }
  21. },
  22. components: {},
  23. data() {
  24. return {
  25. chalk: '', // content of theme-chalk css
  26. theme: ORIGINAL_THEME,
  27. showSuccess: true // 是否弹出换肤成功消息
  28. }
  29. },
  30. computed: {},
  31. watch: {
  32. theme(val, oldVal) {
  33. console.log("theme = ", val, oldVal);
  34. if (typeof val !== 'string') return
  35. const themeCluster = this.getThemeCluster(val.replace('#', ''))
  36. const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
  37. console.log(themeCluster, originalCluster)
  38. const getHandler = (variable, id) => {
  39. return () => {
  40. const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
  41. const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
  42. let styleTag = document.getElementById(id)
  43. if (!styleTag) {
  44. styleTag = document.createElement('style')
  45. styleTag.setAttribute('id', id)
  46. document.head.appendChild(styleTag)
  47. }
  48. styleTag.innerText = newStyle
  49. }
  50. }
  51. const chalkHandler = getHandler('chalk', 'chalk-style')
  52. if (!this.chalk) {
  53. const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
  54. this.getCSSString(url, chalkHandler, 'chalk')
  55. } else {
  56. chalkHandler()
  57. }
  58. const styles = [].slice.call(document.querySelectorAll('style'))
  59. .filter(style => {
  60. const text = style.innerText
  61. return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
  62. })
  63. styles.forEach(style => {
  64. const { innerText } = style
  65. if (typeof innerText !== 'string') return
  66. style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
  67. })
  68. // 响应外部操作
  69. this.$emit('onThemeChange', val)
  70. if (this.showSuccess) {
  71. this.$message({
  72. message: '换肤成功',
  73. type: 'success'
  74. })
  75. } else {
  76. this.showSuccess = true
  77. }
  78. }
  79. },
  80. created() { },
  81. mounted() {
  82. if (this.defaultTheme != null) {
  83. this.theme = this.defaultTheme
  84. this.$emit('onThemeChange', this.theme)
  85. this.showSuccess = false
  86. }
  87. },
  88. methods: {
  89. updateStyle(style, oldCluster, newCluster) {
  90. let newStyle = style
  91. oldCluster.forEach((color, index) => {
  92. newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
  93. })
  94. return newStyle
  95. },
  96. getCSSString(url, callback, variable) {
  97. const xhr = new XMLHttpRequest()
  98. xhr.onreadystatechange = () => {
  99. if (xhr.readyState === 4 && xhr.status === 200) {
  100. this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
  101. callback()
  102. }
  103. }
  104. xhr.open('GET', url)
  105. xhr.send()
  106. },
  107. getThemeCluster(theme) {
  108. const tintColor = (color, tint) => {
  109. let red = parseInt(color.slice(0, 2), 16)
  110. let green = parseInt(color.slice(2, 4), 16)
  111. let blue = parseInt(color.slice(4, 6), 16)
  112. if (tint === 0) { // when primary color is in its rgb space
  113. return [red, green, blue].join(',')
  114. } else {
  115. red += Math.round(tint * (255 - red))
  116. green += Math.round(tint * (255 - green))
  117. blue += Math.round(tint * (255 - blue))
  118. red = red.toString(16)
  119. green = green.toString(16)
  120. blue = blue.toString(16)
  121. return `#${red}${green}${blue}`
  122. }
  123. }
  124. const shadeColor = (color, shade) => {
  125. let red = parseInt(color.slice(0, 2), 16)
  126. let green = parseInt(color.slice(2, 4), 16)
  127. let blue = parseInt(color.slice(4, 6), 16)
  128. red = Math.round((1 - shade) * red)
  129. green = Math.round((1 - shade) * green)
  130. blue = Math.round((1 - shade) * blue)
  131. red = red.toString(16)
  132. green = green.toString(16)
  133. blue = blue.toString(16)
  134. return `#${red}${green}${blue}`
  135. }
  136. const clusters = [theme]
  137. for (let i = 0; i <= 9; i++) {
  138. clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  139. }
  140. clusters.push(shadeColor(theme, 0.1))
  141. return clusters
  142. }
  143. },
  144. updated() { },
  145. beforeDestroy() { },
  146. }
  147. </script>
  148. <style lang='less' rel='stylesheet/less' scoped>
  149. @import "./index.less";
  150. </style>

index.less

  1. .ThemePick {
  2. .theme-picker {
  3. .el-color-picker__trigger {
  4. vertical-align: middle;
  5. }
  6. }
  7. .theme-picker-dropdown {
  8. .el-color-dropdown__link-btn {
  9. display: none;
  10. }
  11. }
  12. }

在组件中引用

  1. <theme-pick @onThemeChange="onThemeChange"></theme-pick>