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