index.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <el-color-picker
  3. v-model="theme"
  4. :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
  5. class="theme-picker"
  6. popper-class="theme-picker-dropdown"
  7. />
  8. </template>
  9. <script>
  10. const version = require('element-ui/package.json').version // element-ui version from node_modules
  11. const ORIGINAL_THEME = '#409EFF' // default color
  12. export default {
  13. data() {
  14. return {
  15. chalk: '', // content of theme-chalk css
  16. theme: ''
  17. }
  18. },
  19. computed: {
  20. defaultTheme() {
  21. return this.$store.state.settings.theme
  22. }
  23. },
  24. watch: {
  25. defaultTheme: {
  26. handler: function(val, oldVal) {
  27. this.theme = val
  28. },
  29. immediate: true
  30. },
  31. async theme(val) {
  32. await this.setTheme(val)
  33. }
  34. },
  35. created() {
  36. if(this.defaultTheme !== ORIGINAL_THEME) {
  37. this.setTheme(this.defaultTheme)
  38. }
  39. },
  40. methods: {
  41. async setTheme(val) {
  42. const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
  43. if (typeof val !== 'string') return
  44. const themeCluster = this.getThemeCluster(val.replace('#', ''))
  45. const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
  46. const $message = this.$message({
  47. message: ' 正在切换主题,请稍后...',
  48. customClass: 'theme-message',
  49. type: 'success',
  50. duration: 0,
  51. iconClass: 'el-icon-loading'
  52. })
  53. const getHandler = (variable, id) => {
  54. return () => {
  55. const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
  56. const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
  57. let styleTag = document.getElementById(id)
  58. if (!styleTag) {
  59. styleTag = document.createElement('style')
  60. styleTag.setAttribute('id', id)
  61. document.head.appendChild(styleTag)
  62. }
  63. styleTag.innerText = newStyle
  64. }
  65. }
  66. if (!this.chalk) {
  67. const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
  68. await this.getCSSString(url, 'chalk')
  69. }
  70. const chalkHandler = getHandler('chalk', 'chalk-style')
  71. chalkHandler()
  72. const styles = [].slice.call(document.querySelectorAll('style'))
  73. .filter(style => {
  74. const text = style.innerText
  75. return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
  76. })
  77. styles.forEach(style => {
  78. const { innerText } = style
  79. if (typeof innerText !== 'string') return
  80. style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
  81. })
  82. this.$emit('change', val)
  83. $message.close()
  84. },
  85. updateStyle(style, oldCluster, newCluster) {
  86. let newStyle = style
  87. oldCluster.forEach((color, index) => {
  88. newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
  89. })
  90. return newStyle
  91. },
  92. getCSSString(url, variable) {
  93. return new Promise(resolve => {
  94. const xhr = new XMLHttpRequest()
  95. xhr.onreadystatechange = () => {
  96. if (xhr.readyState === 4 && xhr.status === 200) {
  97. this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
  98. resolve()
  99. }
  100. }
  101. xhr.open('GET', url)
  102. xhr.send()
  103. })
  104. },
  105. getThemeCluster(theme) {
  106. const tintColor = (color, tint) => {
  107. let red = parseInt(color.slice(0, 2), 16)
  108. let green = parseInt(color.slice(2, 4), 16)
  109. let blue = parseInt(color.slice(4, 6), 16)
  110. if (tint === 0) { // when primary color is in its rgb space
  111. return [red, green, blue].join(',')
  112. } else {
  113. red += Math.round(tint * (255 - red))
  114. green += Math.round(tint * (255 - green))
  115. blue += Math.round(tint * (255 - blue))
  116. red = red.toString(16)
  117. green = green.toString(16)
  118. blue = blue.toString(16)
  119. return `#${red}${green}${blue}`
  120. }
  121. }
  122. const shadeColor = (color, shade) => {
  123. let red = parseInt(color.slice(0, 2), 16)
  124. let green = parseInt(color.slice(2, 4), 16)
  125. let blue = parseInt(color.slice(4, 6), 16)
  126. red = Math.round((1 - shade) * red)
  127. green = Math.round((1 - shade) * green)
  128. blue = Math.round((1 - shade) * blue)
  129. red = red.toString(16)
  130. green = green.toString(16)
  131. blue = blue.toString(16)
  132. return `#${red}${green}${blue}`
  133. }
  134. const clusters = [theme]
  135. for (let i = 0; i <= 9; i++) {
  136. clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  137. }
  138. clusters.push(shadeColor(theme, 0.1))
  139. return clusters
  140. }
  141. }
  142. }
  143. </script>
  144. <style>
  145. .theme-message,
  146. .theme-picker-dropdown {
  147. z-index: 99999 !important;
  148. }
  149. .theme-picker .el-color-picker__trigger {
  150. height: 26px !important;
  151. width: 26px !important;
  152. padding: 2px;
  153. }
  154. .theme-picker-dropdown .el-color-dropdown__link-btn {
  155. display: none;
  156. }
  157. </style>