工程化的Vue项目cdn引入Vue.js和ElementUI方法很简单,不再赘述。
ElementUI提供的样式中,默认的主题色是一种蓝色。工程化的ElementUI主题样式一般都是用sass变量指定,比如
/* 改变主题色变量 */ $--color-primary: $primaryColor; $--color-success: $successColor; $--color-warning: $warningColor; $--color-danger: $errorColor; /* 引用nodemodules中的样式 */ @import "~element-ui/packages/theme-chalk/src/index";
CDN模式下直接在index.html中引用如下css即可应用ElementUI的默认样式。
<link rel='stylesheet' id="chalk-style" href='https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/theme-chalk/index.css' type='text/css' media='all' />
但是一般的vue项目主题色需要自己指定,然而ElementUi又没有提供配置方法。
有人可能知道,ElementUi提供了在线diy主题css的方法 主题生成工具。
这种方式能解决问题,包括下载/theme-chalk/index.css修改后工程中引用。
还有人直接把elementui源码拉了下来,改动主题色变量后编译出来引用。
但是最大的问题是css文件还是要引用到项目中。那使用cdn优化的意义是什么呢?
方案
所以我研究下了,大致思路可以是在vue项目开始访问的时候,动态的js下载/theme-chalk/index.css,脚本替换颜色变量,替换字体为绝对路径,后再append到head中,使样式生效。
import ElementTheme from '../utils/ElementTheme'
mounted () {
ElementTheme.changeTheme("#000000");
}
以下是我调试好的工具类。
//element ui cdn css
const cdn = 'https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M';
const url = `${cdn}/element-ui/2.15.7/theme-chalk/index.css`;
//font url
const fontUrl = `${cdn}/element-ui/2.15.7/theme-chalk/fonts/element-icons`;
//默认蓝色主题
const ORIGINAL_THEME = "#409EFF";
export default{
data: {
chalk: "",
theme: "",
url:url
},
changeTheme(val) {
if (typeof val !== "string" || !val) return;
var that = this;
that.data.theme = val;
//新色
const themeCluster = this.getThemeCluster(val.replace("#", ""));
//原色
const originalCluster = this.getThemeCluster(
ORIGINAL_THEME.replace("#", "")
);
const getHandler = (variable, id) => {
return () => {
const newStyle = this.updateStyle(
that.data[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");
// 判断是否已有样式表,没有则根据url请求样式表内容
if (!this.data.chalk) {
this.getCSSString(this.data.url, chalkHandler, "chalk");
} else {
chalkHandler();
}
},
// 更新主题系列色
updateStyle(style, oldCluster, newCluster) {
let newStyle = style;
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
});
return newStyle;
},
// 初始化时获取默认主题的样式并复制给this.chalk
getCSSString(url, callback, variable) {
const xhr = new XMLHttpRequest();
var that = this;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// that.data[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
that.data[variable] = xhr.responseText.replace('fonts/element-icons', fontUrl);
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) {
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;
},
// /移除全局css
removeGlobalCSS: function (id) {
var head = document.head || document.getElementsByTagName('head')[0]; // 获取head元素
setTimeout(function () {
var tempElement = document.getElementById(id);
if (tempElement) {
head.removeChild(tempElement);
}
}, 200)
},
}
解决上线!
转载请注明:天狐博客 » Vue开发之CDN引入ElementUI后修改主题色的简单方法
