vue-element换肤所有主题色和基础色均可实现自主配置
短信预约 -IT技能 免费直播动态提醒
element换肤所有主题色和基础色均可自主配置
1.element-ui官方提供的动态切换主题方法换肤 但此方法只可修改$–color-primary 这一个主题色及其衍生色
2. 获取element-ui的theme-chalk/index.css文件,找到基础色所对应的颜色值,抽取颜色值进行替换,此种方法无法自动生成衍生色
{
'#67C23A': theme.color_success,
'#E6A23C': theme.color_warning,
'#F56C6C': theme.color_danger,
'#909399': theme.color_info,
}
3.自定义css变量,使用下面的方法去修改变量,此种方法仅可修改自定义的样式
document.documentElement.style.setProperty('--theme-color', value)
最终方案
以上三种相结合,实现我们的需求,各种主题色、基础色自主配置
以下是所有代码
Theme.vue
···ht-form-item
是自定义组件 和 el-form-item
差不多
<template>
<div>
<h4 class="header">
<span>主题配色选择</span>
<el-button type="default" @click="resetTheme">重置</el-button>
</h4>
<el-row>
<el-col :span="8">
<ht-form-item label="主题颜色" label-width="140px">
<el-color-picker
v-model="theme"
:predefine="['#409eff', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="成功颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_success"
:predefine="['#67c23a', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="警告颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_warning"
:predefine="['#e6a23c', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="危险颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_danger"
:predefine="['#f56c6c', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="信息颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_info"
:predefine="['#909399', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="次要主题颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_secondary"
:predefine="['#dfebfc', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
</el-col>
<el-col :span="8">
<ht-form-item label="基础白色" label-width="140px">
<el-color-picker
v-model="themeColor.color_white"
:predefine="['#fff', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="基础黑色" label-width="140px">
<el-color-picker
v-model="themeColor.color_black"
:predefine="['#000', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="主要文字颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_text_primary"
:predefine="['#303133', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="常规文字颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_text_regular"
:predefine="['#606266', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="次要文字颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_text_secondary"
:predefine="['#909399', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="占位文字颜色" label-width="140px">
<el-color-picker
v-model="themeColor.color_text_placeholder"
:predefine="['#c0c4cc', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
</el-col>
<el-col :span="8">
<ht-form-item label="一级边框颜色" label-width="140px">
<el-color-picker
v-model="themeColor.border_color_base"
:predefine="['#dcdfe6', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="二级边框颜色" label-width="140px">
<el-color-picker
v-model="themeColor.border_color_light"
:predefine="['#e4e7ed', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="三级边框颜色" label-width="140px">
<el-color-picker
v-model="themeColor.border_color_lighter"
:predefine="['#ebeef5', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="四级边框颜色" label-width="140px">
<el-color-picker
v-model="themeColor.border_color_extra_light"
:predefine="['#f2f6fc', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="基础背景色" label-width="140px">
<el-color-picker
v-model="themeColor.background_color_base"
:predefine="['#f5f7fa', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
<ht-form-item label="第二基础背景色" label-width="140px">
<el-color-picker
v-model="themeColor.background_color_secondary"
:predefine="['#f0f2f5', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</ht-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<ht-form-item label="首页导航颜色" label-width="140px">
<span class="color-box">
<span class="color-block" :style="{backgroundColor:theme_color}"></span>
</span>
</ht-form-item>
</el-col>
<el-col :span="8">
<ht-form-item label="首页导航悬浮颜色" label-width="140px">
<span class="color-box">
<span class="color-block" :style="{backgroundColor:theme_color_active}"></span>
</span>
</ht-form-item>
</el-col>
</el-row>
</div>
</template>
<script>
import {mapState} from 'vuex';
import variables from '@/assets/css/theme-variables.scss'
const version = require('element-ui/package.json').version
const ORIGINAL_THEME = '#409EFF' // default color
export default {
data() {
return {
themeColor: {},
chalk: '', // content of theme-chalk css
theme: ORIGINAL_THEME,
theme_color: '#0d84ff',
theme_color_active: '#006bd9',
}
},
computed: {
...mapState({
themeVaribles: state => state.theme,
defaultTheme: state => state.theme.color_primary
})
},
watch: {
defaultTheme: {
handler: function(val, oldVal) {
this.theme = val
},
immediate: true
},
themeColor: {
handler: function (theme, oldTheme) {
// element默认主题配色值
this.setIndexStyle(this.getColorMap(theme))
this.setCssVariables(theme)
// vuex存储颜色
for(let x in theme) {
this.$store.dispatch('theme/changeSetting', {
key: x,
value: theme[x]
})
}
localStorage.setItem('themeColor',JSON.stringify(theme))
},
deep: true
},
theme(val,oldVal) {
if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
// console.log(themeCluster, originalCluster)
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
let newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
// 将其他配色添加进去
newStyle = this.getStyleTemplate(newStyle,this.getColorMap(this.themeColor));
let styleTag = document.getElementById(id)
styleTag.innerText = newStyle
}
}
const chalkHandler = getHandler('chalk', 'my-chalk')
chalkHandler()
const styles = [].slice.call(document.querySelectorAll('style'))
.filter(style => {
const text = style.innerText
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
})
styles.forEach(style => {
const { innerText } = style
if (typeof innerText !== 'string') return
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
})
//this.themeColor.color_primary = val
localStorage.setItem('color_primary',val)
this.$store.dispatch('theme/changeSetting', {
key: 'color_primary',
value: val
})
this.theme_color = this.generaterSimilarColor(val,0.1)
this.theme_color_active = this.generaterSimilarColor(val,0.2)
const node = document.documentElement
node.style.setProperty('--theme-color', this.theme_color)
node.style.setProperty('--theme-color-active', this.theme_color_active)
}
},
created() {
// 获取index.css
this.getFile(`//unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`)
.then(({ data }) => {
data = data.replace(/@font-face{[^}]+}/, '')
this.chalk = data
const style = document.createElement('style');
style.id = 'my-chalk'
style.innerText = this.chalk;
document.head.appendChild(style);
// 获取本地存储的基础色
if(localStorage.getItem('themeColor')) {
this.themeColor = JSON.parse(localStorage.getItem('themeColor'))
for(let x in this.themeColor) {
this.$store.dispatch('theme/changeSetting', {
key: x,
value: this.themeColor[x]
})
}
} else {
this.themeColor = Object.assign({},this.themeVaribles)
}
// 获取本地存储的主题色
if(localStorage.getItem("theme")) {
this.theme = localStorage.getItem("theme")
this.$store.dispatch('theme/changeSetting', {
key: 'color_primary',
value: this.theme
})
}
});
},
methods: {
// 重置主题
resetTheme() {
this.theme = ORIGINAL_THEME
let aVariables = {...variables}
delete aVariables.color_primary
this.themeColor = {...aVariables}
},
getColorMap(theme) {
return {
// '#409EFF': theme.color_primary,
'#67C23A': theme.color_success,
'#E6A23C': theme.color_warning,
'#F56C6C': theme.color_danger,
'#909399': theme.color_info,
'#dfebfc': theme.color_secondary,
'#ffffff': theme.color_white,
'#000000': theme.color_black,
'#303133': theme.color_text_primary,
'#606266': theme.color_text_regular,
'#909399': theme.color_text_secondary,
'#C0C4CC': theme.color_text_placeholder,
'#DCDFE6': theme.border_color_base,
'#E4E7ED': theme.border_color_light,
'#EBEEF5': theme.border_color_lighter,
'#F2F6FC': theme.border_color_extra_light,
'#F5F7FA': theme.background_color_base,
'#F0F2F5': theme.background_color_secondary
}
},
// css变量改变赋值
setCssVariables(theme) {
const node = document.documentElement
Object.entries(theme).forEach(ele => {
let key = ele[0].replace(/_/g, '-');
node.style.setProperty(`--${key}`, ele[1])
})
},
// 颜色替换后的样式文件
getStyleTemplate(data,colorMap) {
Object.keys(colorMap).forEach(key => {
const value = colorMap[key];
data = data.replace(new RegExp(key, 'ig'), value);
});
return data;
},
// 获取文件
getFile(url, isBlob = false) {
return new Promise((resolve, reject) => {
const client = new XMLHttpRequest();
client.responseType = isBlob ? 'blob' : '';
client.onreadystatechange = () => {
if (client.readyState !== 4) {
return;
}
if (client.status === 200) {
const urlArr = client.responseURL.split('/');
resolve({
data: client.response,
url: urlArr[urlArr.length - 1]
});
} else {
reject(new Error(client.statusText));
}
};
client.open('GET', url);
client.send();
});
},
// 修改颜色后替换index.css文件
setIndexStyle(colorMap) {
const myChalkStyle = document.getElementById("my-chalk")
const themeCluster = this.getThemeCluster(this.theme.replace('#', ''))
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
let newStyle = this.updateStyle(this.chalk, originalCluster, themeCluster)
newStyle = this.getStyleTemplate(newStyle,colorMap)
myChalkStyle.innerText = newStyle;
},
updateStyle(style, oldCluster, newCluster) {
let newStyle = style
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
})
return newStyle
},
// 获取主题色和衍生色
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
red = Math.round((1 - shade) * red)
green = Math.round((1 - shade) * green)
blue = Math.round((1 - shade) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
}
clusters.push(shadeColor(theme, 0.1))
return clusters
},
// 生成fvue相近主题色:这是一个十六进制转rgb,rgb再转hsl,hsl改变亮度,再转成rgb,再转成十六进制的方法。。。
generaterSimilarColor(color,weight) {
let colorChange = [];
for (let i=1; i<7; i+=2) {
colorChange.push(parseInt("0x"+color.slice(i, i+2)));
}
let [r,g,b] = colorChange
r /= 255, g /= 255, b /= 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max == min){
h = s = 0; // achromatic
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
l = l-weight < 0 ? 0.1 : l-weight
if(s == 0) {
r = g = b = l; // achromatic
} else {
let hue2rgb = function hue2rgb(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
let p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
let rgb = [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
let strHex = "#";
for (let i=0; i<rgb.length; i++) {
let hex = Number(rgb[i]).toString(16);
if (hex.length < 2) {
hex = '0' + hex;
}
strHex += hex;
}
return strHex
}
},
mounted() {
// 获取index.css
this.getFile('/css/theme-chalk/index.css').then(({ data }) => {
data = data.replace(/@font-face{[^}]+}/, '')
this.chalk = data
const style = document.createElement('style')
style.id = 'my-chalk'
style.innerText = this.chalk
document.head.appendChild(style)
// 获取本地存储的基础色
if(localStorage.getItem('themeColor')) {
this.themeColor = JSON.parse(localStorage.getItem('themeColor'))
for(let x in this.themeColor) {
this.$store.dispatch('theme/changeSetting', {
key: x,
value: this.themeColor[x]
})
}
} else {
delete this.themeVaribles.color_primary
this.themeColor = Object.assign({},this.themeVaribles)
}
// 获取本地存储的主题色
if(localStorage.getItem("color_primary")) {
this.theme = localStorage.getItem("color_primary")
this.$store.dispatch('theme/changeSetting', {
key: 'color_primary',
value: this.theme
})
}
});
}
}
</script>
<style lang="scss" scoped>
.header {
font-size: 14px;
text-align: center;
font-weight: normal;
.el-button {
margin-left: 10px;
}
}
.color-box {
display: inline-block;
padding: 4px;
width: 32px;
height: 32px;
border-radius: 4px;
box-sizing: border-box;
border: 1px solid #e6e6e6;
.color-block {
display: inline-block;
width: 100%;
height: 100%;
border-radius: 2px;
}
}
</style>
Theme.js:vuex管理主题色
import themeVariables from '@/assets/css/theme-variables.scss'
const state = {
...themeVariables
}
const getters = {};
const mutations = {
CHANGE_SETTING: (state, { key, value }) => {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(key)) {
state[key] = value
}
}
}
const actions = {
changeSetting({ commit }, data) {
commit('CHANGE_SETTING', data)
}
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
element-variables.scss
// 自定义主题色css变量
// 可使用js修改:document.documentElement.style.setProperty(name,value);
:root {
--color-primary: #409eff;
--color-success: #67c23a;
--color-warning: #e6a23c;
--color-danger: #f56c6c;
--color-info: #909399;
--color-secondary: #dfebfc;
--color-white: #FFFFFF;
--color-black: #000;
--color-text-primary: #303133;
--color-text-regular: #606266;
--color-text-secondary: #909399;
--color-text-placeholder: #c0c4cc;
--border-color-base: #dcdfe6;
--border-color-light: #e4e7ed;
--border-color-lighter: #ebeef5;
--border-color-extra-light: #f2f6fc;
--background-color-base: #f5f7fa;
--background-color-secondary: #f0f2f5;
--theme-color: #2761ff;
--theme-color-active: #1f4ecc;
}
$--color-primary: var(--color-primary);
$--color-success: var(--color-success);
$--color-warning: var(--color-warning);
$--color-danger: var(--color-danger);
$--color-info: var(--color-info);
$--color-secondary: var(--color-secondary);
$--color-white: var(--color-white);
$--color-black: var(--color-black);
$--color-text-primary: var(--color-text-primary);
$--color-text-regular: var(--color-text-regular);
$--color-text-secondary: var(--color-text-secondary);
$--color-text-placeholder: var(--color-text-placeholder);
$--border-color-base: var(--border-color-base);
$--border-color-light: var(--border-color-light);
$--border-color-lighter: var(--border-color-lighter);
$--border-color-extra-light: var(--border-color-extra-light);
$--background-color-base: var(--background-color-base);
$--background-color-secondary: var(--background-color-secondary);
$--theme-color: var(--theme-color);
$--theme-color-active: var(--theme-color-active);
element-custom.scss
@import "theme-variables.scss";
$--font-path: "~element-ui/lib/theme-chalk/fonts";
@import "~element-ui/packages/theme-chalk/class="lazy" data-src/index";
@import "../icon/iconfont.css";
.el-tree-node__label{font-size:12px}
theme-variables.scss
$--theme-color: #2761ff;
$--theme-color-active: #1f4ecc;
$--color-primary: #409eff;
$--color-success: #67c23a;
$--color-warning: #e6a23c;
$--color-danger: #f56c6c;
$--color-info: #909399;
$--color-secondary: #dfebfc;
$--color-white: #ffffff;
$--color-black: #000000;
$--color-text-primary: #303133;
$--color-text-regular: #606266;
$--color-text-secondary: #909399;
$--color-text-placeholder: #c0c4cc;
$--border-color-base: #dcdfe6;
$--border-color-light: #e4e7ed;
$--border-color-lighter: #ebeef5;
$--border-color-extra-light: #f2f6fc;
$--background-color-base: #f5f7fa;
$--background-color-secondary: #f0f2f5;
$--aside-width: 230px;
.primaryColor {
background-color: $--color-primary;
}
//主要的一步:
:export {
theme_color: $--theme-color;
theme_color_active: $--theme-color-active;
color_primary: $--color-primary;
color_success: $--color-success;
color_warning: $--color-warning;
color_danger: $--color-danger;
color_info: $--color-info;
color_secondary: $--color-secondary;
color_white: $--color-white;
color_black: $--color-black;
color_text_primary: $--color-text-primary;
color_text_regular: $--color-text-regular;
color_text_secondary: $--color-text-secondary;
color_text_placeholder: $--color-text-placeholder;
border_color_base: $--border-color-base;
border_color_light: $--border-color-light;
border_color_lighter: $--border-color-lighter;
border_color_extra_light: $--border-color-extra-light;
background_color_base: $--background-color-base;
background_color_secondary: $--background-color-secondary;
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341