1、创建一个vue项目
① vue-cli3创建项目
vue create vue-custom-theme
② 在项目中加入vue.config.js。如下(基本配置)
const path = require('path')
const resolve = dir => {
return path.join(__dirname, dir)
}
module.exports = {
lintOnSave: false,
productionSourceMap: false,
devServer: {
open: true,
port: 8001,
overlay: {
errors: true,
warnings: true
}
},
configureWebpack: {
externals: {
"echarts": "echarts"
},
},
chainWebpack: config => {
config.resolve.alias
.set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
.set('_c', resolve('src/components'))
.set('_m', resolve('src/components/modules'))
.set('_p', resolve('src/components/pages'))
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule
.test(/\.svg$/)
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
}
}
③
安装elementUI
npm i element-ui -S
安装sass
npm install node-sass@4.11.0 sass-loader@7.1.0 -D
启动项目
npm run serve
2、引入element-ui
①在main,js中
import ElementUI from 'element-ui'
import './styles.scss'
Vue.use(ElementUI)
②用户先从线上拉去配置主题的css文件,当用户更改颜色后,在把css文件里面所有的颜色值替换掉,然后把这个css文件重新插入到html中达到改变颜色。
在这里都需要修改再方法1的基础上进行扩展:在element-variables.scss(大部分项目都是)添加 默认我们自己设置的颜色。
当然这个颜色也可以在其他公共css修改。我是在style.scss中修改的,如下
style.scss
/* theme color */
$--color-primary: teal;
/* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
3、主题色修改
①安装两个插件
npm install css-color-function
npm install object-assign
②新建utils文件夹。如下图
color.js 文件内容
import color from 'css-color-function'
import formula from './formula.json'
const generateColors = primary => {
let colors = {}
console.log(primary)
Object.keys(formula).forEach(key => {
const value = formula[key].replace(/primary/g, primary)
colors[key] = color.convert(value)
})
console.log(colors)
return colors
}
export default generateColors
formula.json文件内容:
{
"shade-1": "color(primary shade(10%))",
"light-1": "color(primary tint(10%))",
"light-2": "color(primary tint(20%))",
"light-3": "color(primary tint(30%))",
"light-4": "color(primary tint(40%))",
"light-5": "color(primary tint(50%))",
"light-6": "color(primary tint(60%))",
"light-7": "color(primary tint(70%))",
"light-8": "color(primary tint(80%))",
"light-9": "color(primary tint(90%))"
}
③ 从 unpkg.com/element-ui/lib/theme-chalk/index.css 把最新css文件复制下来copy到项目静态文件目录中:
因为:项目中是先从element官方拉取主题css,如果拉取不到再去本地找备用的。
④ 接下来就是写代码了。在App.vue上引入自定义的修改主题组件,在随便弄些element组件观察变化:
⑤写组件:Theme.vue
<!-- 切换主题色 -->
<template>
<div>
<el-color-picker @change="colorChange" v-model="colors.primary" ></el-color-picker>
</div>
</template>
<script>
import generateColors from "@/utils/color";
import objectAssign from "object-assign";
export default {
name: "App",
data() {
return {
originalStylesheetCount: -1,//记录当前已引入style数量
originalStyle: "",//获取拿到的.css的字符串
colors: {
//颜色选择器默认颜色值,这个值要和element-variables一样
primary: "#409EFF"
},
// primaryColor: "", //提交成功后设置默认颜色
cssUrl: [
"//unpkg.com/element-ui/lib/theme-chalk/index.css",
"/static/css/index.css"
]
};
},
methods: {
colorChange(e) {
if(!e)return;
localStorage.setItem('color',e)
this.primaryColor = this.colors.primary;
this.colors = objectAssign(
{},
this.colors,
generateColors(this.colors.primary)
);
this.writeNewStyle();
},
writeNewStyle() {
let cssText = this.originalStyle;
Object.keys(this.colors).forEach(key => {
cssText = cssText.replace(
new RegExp("(:|\\s+)" + key, "g"),
"$1" + this.colors[key]
);
});
if (this.originalStylesheetCount === document.styleSheets.length) {
// 如果之前没有插入就插入
const style = document.createElement("style");
style.innerText =
".primaryColor{background-color:" + this.colors.primary + "}" + cssText;
document.head.appendChild(style);
} else {
// 如果之前没有插入就修改
document.head.lastChild.innerText =
".primaryColor{background-color:" +
this.colors.primary +
"} " +
cssText;
}
},
getIndexStyle(url) {
let that = this;
var request = new XMLHttpRequest();
request.open("GET", url);
request.onreadystatechange = function() {
if (
request.readyState === 4 &&
(request.status == 200 || request.status == 304)
) {
// 调用本地的如果拿不到会得到html,html是不行的
if (request.response && !/DOCTYPE/gi.test(request.response)) {
that.originalStyle = that.getStyleTemplate(request.response);
that.writeNewStyle()
} else {
that.originalStyle = "";
}
} else {
that.originalStyle = "";
}
};
request.send(null);
},
getStyleTemplate(data) {
const colorMap = {
"#3a8ee6": "shade-1",
"#409eff": "primary",
"#53a8ff": "light-1",
"#66b1ff": "light-2",
"#79bbff": "light-3",
"#8cc5ff": "light-4",
"#a0cfff": "light-5",
"#b3d8ff": "light-6",
"#c6e2ff": "light-7",
"#d9ecff": "light-8",
"#ecf5ff": "light-9"
};
Object.keys(colorMap).forEach(key => {
const value = colorMap[key];
data = data.replace(new RegExp(key, "ig"), value);
});
return data;
}
},
mounted() {
// 默认从线上官方拉取最新css,2秒钟后做一个检查没有拉到就从本地在拉下
let that = this;
// 如果是记住用户的状态就需要,在主题切换的时候记录颜色值,在下次打开的时候从新赋值
this.colors.primary = localStorage.getItem('color')||this.colors.primary//例如
this.getIndexStyle(this.cssUrl[0]);
setTimeout(function() {
if (that.originalStyle) {
return;
} else {
that.getIndexStyle(that.cssUrl[1]);
}
}, 2000);
this.$nextTick(() => {
// 获取页面一共引入了多少个style 文件
this.originalStylesheetCount = document.styleSheets.length;
});
}
};
</script>
<style>
</style>