element主题色切换

element主题色切换,第1张

在网上搜了很多主题切换方案,发现没有适合自己项目的,不得已结合根据实际情况做一个子主题切换的功能。其中参考了element 官方的theme-chalk-preview,感兴趣的可以自己研究一下

主要功能是基于less切换主题色,可以自定义颜色,同时结合VuexlocalStorage对主题色进行缓存,在下次进入项目时初始化

代码地址:theme-chalk-preview代码
预览地址:theme-chalk-preview预览

首先说一下我的项目环境: Vue: 2.6.10Less: 3.9.0Element: 2.15.6css-color-function: 1.3.3 代码编写 由于项目需要对主题色进行缓存,所以主要代码编写在Vueapp.vue文件下,以确保在初始化时能及时获取主题色配置 1. Vuex相关
state: {
	theme: localStorage.getItem('theme') || '#409EFF',
  	originalStyle: ''
 }
mutations: {
  // 设置主题颜色
  setTheme(state, color) {
    state.themeColor = color;
	localStorage.setItem('themeColor', color);
  },
  // 获取element 默认样式文件
  setStyle(state, data) {
    state.originalStyle = data
  },
}
getters: {
  theme: state => state.theme,
  originalStyle: state => state.originalStyle
}

Vuex中声明了两个变量,然后通过mutations和getters对变量进行获取和赋值


1、theme,表示当前主题色,由于是存储在localStorage中的,所以先从localStorage中获取,然后才是基准色,我的基准色采用的是Element的默认颜色#409eff


2、originalStyle,这个变量存放的是element某个主题颜色的基础样式文件(element-ui的默认样式文件),其实本次主题切换的实质就是在element的基础样式文件上进行,通过修改该文件中的颜色值来切换主题。放在vuex中的目的是我的需求中有多个地方可以切换主题色,方便获取,以免重复下载样式文件

2.新建color工具函数文件(用来替换主题样式文件中的颜色值)
//   util/color.js
import color from 'css-color-function'

// 基于 primary变量 生成颜色键值对
const formula = {
  "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%))"
}

const generateColors = primary => {
  let colors = {}

  Object.keys(formula).forEach(key => {
  	// 此处通过传入的primary颜色将formula对象中的值转换成RGB格式的颜色
    const value = formula[key].replace(/primary/g, primary)
    // 设置RGB颜色值
    colors[key] = color.convert(value)
  })
  return colors
}
/** eg: 

	const colors = generateColor('#409eff')
	colos => {
	    "shade-1": "rgb(58, 142, 230)",
	    "light-1": "rgb(83, 168, 255)",
	    "light-2": "rgb(102, 177, 255)",
	    "light-3": "rgb(121, 187, 255)",
	    "light-4": "rgb(140, 197, 255)",
	    "light-5": "rgb(160, 207, 255)",
	    "light-6": "rgb(179, 216, 255)",
	    "light-7": "rgb(198, 226, 255)",
	    "light-8": "rgb(217, 236, 255)",
	    "light-9": "rgb(236, 245, 255)"
	}
	
*/
export default generateColors
3.App.vue文件 声明color变量:
data() {
	return {
		colors: {
			primary: "", // 默认颜色
		},
	};
},
引入generateColors方法:
import generateColors from "@/util/color";
获取vuex中声明的变量
import { mapGetters, mapMutations} from "vuex";
export default {
	computed: {
		...mapGetters(["themeColor", "originalStyle"]),
	},
	methods: {
		...mapMutations(['setStyle', 'setTheme']),
	}
}
下载css文件并替换文件中的颜色值:
export default {
	methods: {
		...mapMutations(['setStyle', 'setTheme']),
		// 该方法是将样式文件中的颜色值替换成键值对中的value(primary、light-n、shade-1)
		getStyleTemplate(data) {
			// 具体颜色值可参考上面提到的官方案例theme-chalk-preview
			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;
		},
		// 主方法,可在页面内初始化的时候请求
		getIndexStyle() {
			// 这里可以根据自己的element版本下载指定版本
			this.getFile(
				`//unpkg.com/element-ui@2.15.6/lib/theme-chalk/index.css`
			).then(({ data }) => {
				// 进行颜色值替换,同时将替换后的样式文件保存到vuex中,方便其他地方获取(按你自己的需求来存放)
				this.setStyle(this.getStyleTemplate(data));
				// 根据传入的themeColor生成颜色键值对
				this.colors = Object.assign(
					this.colors,
					generateColors(this.themeColor)
				);
				// 生成样式文件插入到页面根节点
				this.writeNewStyle();
			});
		},
		// 传入url,下载指定样式文件
		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();
			});
		},
	}
	writeNewStyle() {
		// 这里获取到的cssText是将文件中的颜色值替换为(primary、light-n、shade-1)过后的
		let cssText = this.originalStyle;
		/** 
			此时this.colors的值为:
			{
			    "primary": "#409eff",
			    "shade-1": "rgb(58, 142, 230)",
			    "light-1": "rgb(83, 168, 255)",
			    "light-2": "rgb(102, 177, 255)",
			    "light-3": "rgb(121, 187, 255)",
			    "light-4": "rgb(140, 197, 255)",
			    "light-5": "rgb(160, 207, 255)",
			    "light-6": "rgb(179, 216, 255)",
			    "light-7": "rgb(198, 226, 255)",
			    "light-8": "rgb(217, 236, 255)",
			    "light-9": "rgb(236, 245, 255)"
			}
			然后再将cssText中的(primary、light-n、shade-1)替换成当前主题色的颜色值
		*/
		Object.keys(this.colors).forEach((key) => {
			cssText = cssText.replace(
				new RegExp("(:|\s+)" + key, "g"),
				"" + this.colors[key]
			);
		});
		// 接下来在dom插入样式文件
		let styleTag = document.getElementById("chalk-style");
		if (!styleTag) {
			styleTag = document.createElement("style");
			styleTag.innerText = cssText;
			styleTag.setAttribute("id", "chalk-style");
			document.head.appendChild(styleTag);
			} else {
				styleTag.innerText = cssText;
			}
			this.$store.commit("setTheme", this.colors.primary);
		},
	},
}
修改成功后可以在head进行查看
展开找到我们之前声明id为chalk-style的style文件,到这里已经修改完成了
这时候如果要更改主题色,只需要修改color.primary的值就行了
export default {
	created() {
		this.colors.primary = this.themeColor;
		this.getIndexStyle();
	},
}
app.vue完整代码
<template>
	<div id="app">
		<router-view/>
	div>
template>
<script>
import { mapGetters, mapMutations } from "vuex";
import generateColors from "@/util/color";
export default {
	data() {
		return {
			colors: {
				primary: "",
			},
		};
	},
	computed: {
		...mapGetters(["themeColor", "originalStyle"]),
	},
	created() {
		this.colors.primary = this.themeColor;
		this.getIndexStyle();
	},
	methods: {
    	...mapMutations(['setStyle', 'setTheme']),
		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;
		},
		getIndexStyle() {
			this.getFile(
				`//unpkg.com/element-ui@2.15.6/lib/theme-chalk/index.css`
			).then(({ data }) => {
        	this.setStyle(this.getStyleTemplate(data))
				this.colors = Object.assign(
					this.colors,
					generateColors(this.themeColor)
				);
				this.writeNewStyle();
			});
		},
		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();
			});
		},
		writeNewStyle() {
			let cssText = this.originalStyle;
			Object.keys(this.colors).forEach((key) => {
				cssText = cssText.replace(
					new RegExp("(:|\s+)" + key, "g"),
					"" + this.colors[key]
				);
			});
			let styleTag = document.getElementById("chalk-style");
			if (!styleTag) {
				styleTag = document.createElement("style");
				styleTag.innerText = cssText;
				styleTag.setAttribute("id", "chalk-style");
				document.head.appendChild(styleTag);
			} else {
				styleTag.innerText = cssText;
			}
      		this.setTheme(this.colors.primary)
		},
	},
};
script>
<style lang="less">
style>

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/946101.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-18
下一篇 2022-05-18

发表评论

登录后才能评论

评论列表(0条)

保存