封装了两个element ui 颜色选择器,一个是本地储存(local storage)保存颜色,并不需要调取接口即可保存用户的改变的主题颜色。另外一个是改变颜色之后,刷新页面改变的颜色就会变回原来的初始值。需要哪一个看你个人选择。
本地储存颜色:
1.首先封装一个colorPicker组件
<template>
<el-color-picker
v-model="theme"
class="theme-picker"
:predefine="predefineColors"
popper-class="theme-picker-dropdown"
>
</el-color-picker>
</template>
<script>
const version = require("element-ui/package.json").version; // 版本号
const ORIGINAL_THEME = "#409EFF";
export default {
name: "colorPicker",
data() {
return {
chalk: "",
theme: ORIGINAL_THEME,
predefineColors: [
"#409EFF",
"#ff4500",
"#ff8c00",
"#ffd700",
"#90ee90",
"#00ced1",
"#1e90ff",
"#c71585"
]
};
},
mounted() {
if (this.CheckIsColor(localStorage.getItem("colorPicker"))) {
this.theme = localStorage.getItem("colorPicker");
}
},
watch: {
theme(val, oldVal) {
if (typeof val !== "string") return;
localStorage.setItem("colorPicker", val);
const themeCluster = this.getThemeCluster(val.replace("#", ""));
const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(
ORIGINAL_THEME.replace("#", "")
);
const newStyle = this.updateStyle(
this[variable],
originalCluster,
themeCluster
);
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement("style");
styleTag.setAttribute("id", id);
document.head.appendChild(styleTag);
}
styleTag.innerText = newStyle;
};
};
const chalkHandler = getHandler("chalk", "chalk-style");
if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
this.getCSSString(url, chalkHandler, "chalk");
} else {
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
);
});
/* 当颜色改变时,使用vuex储存改变的颜色值 */
this.$store.commit({
type: "getThemeColor",
color: val
});
}
},
methods: {
CheckIsColor(bgVal) {
var type = "^#[0-9a-fA-F]{6}$";
var re = new RegExp(type);
if (bgVal.match(re) == null) {
type =
// eslint-disable-next-line no-useless-escape
"^[rR][gG][Bb][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){2}[\\s]*(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)[\\s]*[\)]{1}$";
re = new RegExp(type);
if (bgVal.match(re) == null) {
return false;
} else {
return true;
}
} else {
return true;
}
},
updateStyle(style, oldCluster, newCluster) {
let newStyle = style;
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
});
return newStyle;
},
getCSSString(url, callback, variable) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
callback();
}
};
xhr.open("GET", url);
xhr.send();
},
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;
}
}
};
</script>
<style>
.theme-picker .el-color-picker__trigger {
vertical-align: middle;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>
然后在vuex里面
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
/* 默认的主题颜色 */
themeColor: "#409EFF"
},
getters: {},
mutations: {
getThemeColor(state, payload) {
state.themeColor = payload.color;
}
},
actions: {}
});
然后在main.js里面全局引入一下这个vuex的变量(如果不需要全局引用的话也可以按需引入)
import { mapState } from "vuex";
//全局混入
Vue.mixin({
data() {
return {};
},
computed: {
...mapState(["themeColor"])
},
mounted() {},
methods: {}
});
好了,现在就可以在全局中使用了。
效果如下:
<template>
<div class="two" :style="{ color: themeColor }">
<h1>哈哈哈</h1>
<el-row>
<el-col :span="6"> </el-col>
<el-col :span="6">
<el-date-picker v-model="value1" type="date" placeholder="选择日期">
</el-date-picker>
</el-col>
<el-col :span="6">
<el-button type="primary">主要按钮</el-button>
</el-col>
</el-row>
</div>
</template>
刷新页面之后,改变的主题颜色值还在。
第二种方法,刷新之后就变回原来的颜色
首先要安装sass-loader和node-sass
npm install sass-loader
cnpm install node-sass@latest
首先还是封装好一个组件先:
<template>
<el-color-picker
v-model="theme"
:predefine="[
'#409EFF',
'#1890ff',
'#304156',
'#212121',
'#11a983',
'#13c2c2',
'#6959CD',
'#f5222d'
]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</template>
<script>
const version = require("element-ui/package.json").version; // element-ui version from node_modules
const ORIGINAL_THEME = "#409EFF"; // default color
export default {
data() {
return {
chalk: "", // content of theme-chalk css
theme: ""
};
},
computed: {
defaultTheme() {
return this.$store.state.settings.themeColor;
}
},
watch: {
defaultTheme: {
// eslint-disable-next-line no-unused-vars
handler: function(val, oldVal) {
this.theme = val;
},
immediate: true
},
async theme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
if (typeof val !== "string") return;
const themeCluster = this.getThemeCluster(val.replace("#", ""));
const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
console.log(themeCluster, originalCluster);
const $message = this.$message({
message: " Compiling the theme",
customClass: "theme-message",
type: "success",
duration: 0,
iconClass: "el-icon-loading"
});
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(
ORIGINAL_THEME.replace("#", "")
);
const newStyle = this.updateStyle(
this[variable],
originalCluster,
themeCluster
);
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement("style");
styleTag.setAttribute("id", id);
document.head.appendChild(styleTag);
}
styleTag.innerText = newStyle;
};
};
if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
await this.getCSSString(url, "chalk");
}
const chalkHandler = getHandler("chalk", "chalk-style");
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.$emit("change", val);
$message.close();
}
},
methods: {
updateStyle(style, oldCluster, newCluster) {
let newStyle = style;
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
});
return newStyle;
},
getCSSString(url, variable) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
resolve();
}
};
xhr.open("GET", url);
xhr.send();
});
},
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;
}
}
};
</script>
<style>
.theme-message,
.theme-picker-dropdown {
z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
height: 26px !important;
width: 26px !important;
padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>
然后创建一个vuex,这里建议创建一个modules单独配置
整体的vuex代码
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context("./modules", true, /\.js$/);
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
const value = modulesFiles(modulePath);
modules[moduleName] = value.default;
return modules;
}, {});
const store = new Vuex.Store({
modules
});
export default store;
在modules里面创建一个settings.js文件
单独的模块代码:
import variables from "@/styles/element-variables.scss";
const state = {
themeColor: variables.theme
};
const mutations = {
CHANGE_SETTING: (state, { key, value }) => {
if (state.hasOwnProperty(key)) {
state[key] = value;
}
}
};
const actions = {
changeSetting({ commit }, data) {
commit("CHANGE_SETTING", data);
}
};
export default {
namespaced: true,
state,
mutations,
actions
};
element-variables.scss代码:
/**
* I think element-ui's default theme color is too light for long-term use.
* So I modified the default color and you can modify it to your liking.
**/
/* theme color */
$--color-primary: #1890ff;
$--color-success: #13ce66;
$--color-warning: #FFBA00;
$--color-danger: #ff4949;
// $--color-info: #1E1E1E;
$--button-font-weight: 400;
// $--color-text-regular: #1f2d3d;
$--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5;
$--table-border:1px solid#dfe6ec;
/* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
theme: $--color-primary;
}
为了可以改变除了element ui之外的组件颜色,在main.js里面全局混入:
import { mapState } from "vuex";
//全局混入
Vue.mixin({
data() {
return {};
},
computed: {
...mapState("settings", ["themeColor"])
},
mounted() {},
methods: {}
});
好了现在就可以使用了,使用代码如下:
<template>
<div id="app">
<div id="nav">
<color-picker @change="themeChange"></color-picker>
</div>
<router-view />
</div>
</template>
<script>
import colorPicker from "@/components/color_picker/ColorPicker";
export default {
components: {
colorPicker
},
mounted() {},
methods: {
themeChange(val) {
this.$store.dispatch("settings/changeSetting", {
key: "themeColor",
value: val
});
}
}
};
</script>
效果如下:
<h1 :style="{ color: themeColor }">哈哈哈</h1>
刷新页面之后就恢复原来的初始值了,这个方法适用于调接口使用(根据每个不同的用户配置他们各自的主题色,这个具体的做法需要后端配合)
这里附上一下我是如何调接口的
created(){
/* 初始化themeColor的值 */
this.$store.dispatch('settings/changeSetting', {
key: 'themeColor',
value: ''
})
/* 一开始先得到初始的颜色值,然后上传到vuex */
getDictViewConfig({
viewConfigType: '01'
}).then(res => {
this.$store.dispatch('settings/changeSetting', {
key: 'themeColor',
value: res.data.viewConfigValue
})
})
},
methods:{
themeChange (val) {
modifyDictViewConfig({
viewConfigType: '01',
viewConfigValue: val
}).then(res => {
if (res.code === 200) {
getDictViewConfig({
viewConfigType: '01'
}).then(res => {
this.$store.dispatch('settings/changeSetting', {
key: 'themeColor',
value: res.data.viewConfigValue
})
})
}
})
}
}
如果有不明白的地方可以留言大家一起交流一下。