themeCom.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <template>
  2. <el-color-picker v-model="theme" />
  3. </template>
  4. <script>
  5. const version = require("element-ui/package.json").version;
  6. const ORIGINAL_THEME = "#409EFF";
  7. export default {
  8. props: {
  9. color: String,
  10. },
  11. data() {
  12. return {
  13. chalk: "",
  14. theme: "",
  15. };
  16. },
  17. computed: {
  18. defaultTheme() {
  19. return this.color;
  20. },
  21. },
  22. watch: {
  23. defaultTheme: {
  24. handler: function (val, oldVal) {
  25. this.theme = val;
  26. },
  27. immediate: true,
  28. },
  29. async theme(val) {
  30. const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
  31. if (typeof val !== "string") return;
  32. const themeCluster = this.getThemeCluster(val.replace("#", ""));
  33. const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
  34. if (!this.chalk) {
  35. await this.getCSSString();
  36. }
  37. this.getHandler(themeCluster);
  38. const styles = [].slice
  39. .call(document.querySelectorAll("style"))
  40. .filter((style) => {
  41. const text = style.innerText;
  42. return (
  43. new RegExp(oldVal, "i").test(text) && !/Chalk Variables/.test(text)
  44. );
  45. });
  46. styles.forEach((style) => {
  47. const { innerText } = style;
  48. if (typeof innerText !== "string") return;
  49. style.innerText = this.updateStyle(
  50. innerText,
  51. originalCluster,
  52. themeCluster
  53. );
  54. });
  55. this.$emit("color-update", val);
  56. },
  57. },
  58. methods: {
  59. // 修改element-ui主题样式表颜色
  60. updateStyle(style, oldCluster, newCluster) {
  61. let newStyle = style;
  62. oldCluster.forEach((color, index) => {
  63. newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
  64. });
  65. return newStyle;
  66. },
  67. // 生成新的样式表
  68. getHandler(themeCluster) {
  69. const originalCluster = this.getThemeCluster(
  70. ORIGINAL_THEME.replace("#", "")
  71. );
  72. const newStyle = this.updateStyle(
  73. this.chalk,
  74. originalCluster,
  75. themeCluster
  76. );
  77. let styleTag = document.getElementById("chalk-style");
  78. if (!styleTag) {
  79. styleTag = document.createElement("style");
  80. styleTag.setAttribute("id", "chalk-style");
  81. document.head.appendChild(styleTag);
  82. }
  83. styleTag.innerText = newStyle;
  84. },
  85. // 获取element-ui主题样式
  86. getCSSString() {
  87. const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
  88. return new Promise((resolve) => {
  89. const xhr = new XMLHttpRequest();
  90. xhr.onreadystatechange = () => {
  91. if (xhr.readyState === 4 && xhr.status === 200) {
  92. this.chalk = xhr.responseText.replace(/@font-face{[^}]+}/, "");
  93. resolve();
  94. }
  95. };
  96. xhr.open("GET", url);
  97. xhr.send();
  98. });
  99. },
  100. getThemeCluster(theme) {
  101. const tintColor = (color, tint) => {
  102. let red = parseInt(color.slice(0, 2), 16);
  103. let green = parseInt(color.slice(2, 4), 16);
  104. let blue = parseInt(color.slice(4, 6), 16);
  105. if (tint === 0) {
  106. return [red, green, blue].join(",");
  107. } else {
  108. red += Math.round(tint * (255 - red));
  109. green += Math.round(tint * (255 - green));
  110. blue += Math.round(tint * (255 - blue));
  111. red = red.toString(16);
  112. green = green.toString(16);
  113. blue = blue.toString(16);
  114. return `#${red}${green}${blue}`;
  115. }
  116. };
  117. const shadeColor = (color, shade) => {
  118. let red = parseInt(color.slice(0, 2), 16);
  119. let green = parseInt(color.slice(2, 4), 16);
  120. let blue = parseInt(color.slice(4, 6), 16);
  121. red = Math.round((1 - shade) * red);
  122. green = Math.round((1 - shade) * green);
  123. blue = Math.round((1 - shade) * blue);
  124. red = red.toString(16);
  125. green = green.toString(16);
  126. blue = blue.toString(16);
  127. return `#${red}${green}${blue}`;
  128. };
  129. const clusters = [theme];
  130. for (let i = 0; i <= 9; i++) {
  131. clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
  132. }
  133. clusters.push(shadeColor(theme, 0.1));
  134. return clusters;
  135. },
  136. },
  137. };
  138. </script>