theme-picker.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <el-color-picker
  3. class="theme-picker"
  4. popper-class="theme-picker-dropdown"
  5. v-model="theme"></el-color-picker>
  6. </template>
  7. <style>
  8. .theme-picker {
  9. height: 80px;
  10. display: inline-block;
  11. @utils-vertical-center;
  12. }
  13. .theme-picker .el-color-picker__trigger {
  14. vertical-align: middle;
  15. }
  16. .theme-picker-dropdown .el-color-dropdown__link-btn {
  17. display: none;
  18. }
  19. </style>
  20. <script>
  21. import Element from 'main/index.js';
  22. const { version } = Element;
  23. const ORIGINAL_THEME = '#409EFF';
  24. export default {
  25. data() {
  26. return {
  27. chalk: '', // content of theme-chalk css
  28. docs: '', // content of docs css
  29. theme: ORIGINAL_THEME
  30. };
  31. },
  32. watch: {
  33. theme(val, oldVal) {
  34. if (typeof val !== 'string') return;
  35. const themeCluster = this.getThemeCluster(val.replace('#', ''));
  36. const originalCluster = this.getThemeCluster(oldVal.replace('#', ''));
  37. const getHandler = (variable, id) => {
  38. return () => {
  39. const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''));
  40. let newStyle = this.updateStyle(this[variable], originalCluster, themeCluster);
  41. let styleTag = document.getElementById(id);
  42. if (!styleTag) {
  43. styleTag = document.createElement('style');
  44. styleTag.setAttribute('id', id);
  45. document.head.appendChild(styleTag);
  46. }
  47. styleTag.innerText = newStyle;
  48. };
  49. };
  50. const chalkHandler = getHandler('chalk', 'chalk-style');
  51. const docsHandler = getHandler('docs', 'docs-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. if (!this.docs) {
  59. const links = [].filter.call(document.querySelectorAll('link'), link => {
  60. return /docs\..+\.css/.test(link.href || '');
  61. });
  62. links[0] && this.getCSSString(links[0].href, docsHandler, 'docs');
  63. } else {
  64. docsHandler();
  65. }
  66. const styles = [].slice.call(document.querySelectorAll('style'))
  67. .filter(style => {
  68. const text = style.innerText;
  69. return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text);
  70. });
  71. styles.forEach(style => {
  72. const { innerText } = style;
  73. if (typeof innerText !== 'string') return;
  74. style.innerText = this.updateStyle(innerText, originalCluster, themeCluster);
  75. });
  76. }
  77. },
  78. methods: {
  79. updateStyle(style, oldCluster, newCluster) {
  80. let newStyle = style;
  81. oldCluster.forEach((color, index) => {
  82. newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]);
  83. });
  84. return newStyle;
  85. },
  86. getCSSString(url, callback, variable) {
  87. const xhr = new XMLHttpRequest();
  88. xhr.onreadystatechange = () => {
  89. if (xhr.readyState === 4 && xhr.status === 200) {
  90. this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '');
  91. callback();
  92. }
  93. };
  94. xhr.open('GET', url);
  95. xhr.send();
  96. },
  97. getThemeCluster(theme) {
  98. const tintColor = (color, tint) => {
  99. let red = parseInt(color.slice(0, 2), 16);
  100. let green = parseInt(color.slice(2, 4), 16);
  101. let blue = parseInt(color.slice(4, 6), 16);
  102. if (tint === 0) { // when primary color is in its rgb space
  103. return [red, green, blue].join(',');
  104. } else {
  105. red += Math.round(tint * (255 - red));
  106. green += Math.round(tint * (255 - green));
  107. blue += Math.round(tint * (255 - blue));
  108. red = red.toString(16);
  109. green = green.toString(16);
  110. blue = blue.toString(16);
  111. return `#${ red }${ green }${ blue }`;
  112. }
  113. };
  114. const shadeColor = (color, shade) => {
  115. let red = parseInt(color.slice(0, 2), 16);
  116. let green = parseInt(color.slice(2, 4), 16);
  117. let blue = parseInt(color.slice(4, 6), 16);
  118. red = Math.round((1 - shade) * red);
  119. green = Math.round((1 - shade) * green);
  120. blue = Math.round((1 - shade) * blue);
  121. red = red.toString(16);
  122. green = green.toString(16);
  123. blue = blue.toString(16);
  124. return `#${ red }${ green }${ blue }`;
  125. };
  126. const clusters = [theme];
  127. for (let i = 0; i <= 9; i++) {
  128. clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
  129. }
  130. clusters.push(shadeColor(theme, 0.1));
  131. return clusters;
  132. }
  133. }
  134. };
  135. </script>