背景
ElementUI组件库相信大家一定都接触过。但是自定义主题颜色的需求有接触过的应该不多,至少我到今天是没有遇到类似的需求。之所以讲这个需求,是因为在我个人开发的开源项目中有做到这个需求,所以在这里和大家聊一聊我的实现。
CSS变量
在此之前我们需要先了解一下
CSS变量
:它是自定义属性(有时候也被称作
CSS变量
或者
级联变量
)是由
CSS
作者定义的,它包含的值可以在整个文档中重复使用。由自定义属性标记设定值,由
var()
函数来获取值。
/* 设定值 */:root{--background-color: #FF0000;}/* 获取值 */div{background-color:var(--background-color);}
Element主题色
由Element官方文档我们可以它的整个组件库都是使用的
CSS变量
实现的。并且它提供了四种方式来修改样式变量,具体方式可以参考官方文档。
我这边主要介绍的就是Element通过
js
控制
CSS变量
设置的方式。那就会有两个问题:
如何通过
js
获取到
CSS变量
js
获取
CSS变量
那就要介绍这个方法getComputedStyle():它返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有 CSS 属性的值。它有两个参数:第一个参数就是用于获取计算样式的Element;第二个参数是可选参数,是指定一个要匹配的伪元素的字符串。返回的
style
是一个实时的 CSSStyleDeclaration 对象,当元素的样式更改时,它会自动更新本身。CSSStyleDeclaration对象中的getPropertyValue()接口返回一个DOMString,其中包含请求的
CSS
属性的值。
const element = document.documentElement;const style = window.getComputedStyle(element);const value = style.getPropertyValue('`background-color`');
如何通过
js
设置
CSS变量
js
设置
CSS变量
那就要介绍CSSStyleDeclaration对象中的setProperty()接口,它有三个参数:第一个参数是一个DOMString,代表被更改的
CSS
属性;第二个参数是一个可选参数也是一个DOMString,含有新的属性值。如果没有指定,则当作空字符串;第三个参数是一个可选参数,是一个 DOMString 允许设置 “important” CSS 优先级。如果没有指定,则当作空字符串。
有了以上两个方法那我们就可以通过
js
直接修改Element的主题色了,简单实现一下:
<template>
<div class="container">
<el-button>Default</el-button>
<el-button v-for="item in types" :key="item" :type="item">{{ item }}</el-button>
<hr>
<el-radio-group v-model="radio" @change="radioChangeHandle">
<el-radio v-for="item in types" :key="item" :label="item" size="large">{{ item }}</el-radio>
</el-radio-group>
<br>
<el-color-picker v-model="color" @change="colorChangeHandle" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const el = document.documentElement
const types = ref(['primary', 'success', 'info', 'warning', 'danger'])
const radio = ref('primary')
const color = ref('')
const radioChangeHandle = () => {
const value = getComputedStyle(el).getPropertyValue(`--el-color-${radio.value}`)
color.value = value
}
const colorChangeHandle = (value) => {
el.style.setProperty(`--el-color-${radio.value}`, value)
}
</script>
<style>
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -100%);
width: 50%;
text-align: center;
}
</style>
通过以上方式修改了之后,所有的组件的颜色都已经修改了,并且已经达到了效果。但是其中还存在一个问题,以
el-button
组件举例。每个按钮组件都会有个
hover
的颜色,虽然显示的颜色已经修改了,但是
hover
的颜色还是原来的颜色,这是一个严重的
Bug
。原因是按钮的组件
hover
的颜色使用了其
CSS变量
。
颜色的HEX格式
颜色的
HEX
格式是
#
,其中六位数字/字母
是一种十六进制的表达方式。这六位分别两个一组,从左到右分别表示六位数字/字母
、红
、绿
。蓝
表示最小,十进制是00
;0
表示最大,十进制是FF
。通俗点讲,某个颜色的数值越大,包含这个颜色就越多。如:255
#000000
-黑色、
#FFFFFF
-白色、
#FF0000
-红色、
#00FF00
-绿色、
#0000FF
-蓝色。
HEX格式颜色变亮、变暗
通过上文的介绍,我们可以知道Element的
hover
颜色变亮了,即颜色的数值变大了,那我们只要对要修改的颜色数值变大即可。那就需要用到以下的方法:
HEX格式转RGB格式
hex2Rgb(color){
color = color.replace('#','')const result = color.match(/../g)for(let i =0; i <3; i++){
result[i]=parseInt(result[i],16)}return result
}
RGB格式转HEX格式
rgb2Hex(r, g, b){const hexs =[r.toString(16), g.toString(16), b.toString(16)]for(let i =0; i <3; i++){if(hexs[i].length ===1){
hexs[i]='0'+ hexs[i]}}const result ='#'+ hexs.join('')return result
}
使颜色变亮
lighten(color, level){const rgb =hex2Rgb(color)for(let i =0; i <3; i++){
rgb[i]= Math.floor((255- rgb[i])* level + rgb[i])}const result =rgb2Hex(rgb[0], rgb[1], rgb[2])return result
}
使颜色变暗
darken(color, level){const rgb =hex2Rgb(color)for(let i =0; i <3; i++){
rgb[i]= Math.floor(rgb[i]*(1- level))}const result =rgb2Hex(rgb[0], rgb[1], rgb[2])return result
}
解决问题
有了上文的几个方法,我们就可以在修改主色的时候将对应的其他
CSS变量
进行变亮或者变暗即可。一般这种主题都是会存储浏览器
Storage
中,大家可以结合实际情况配合
vuex
或者
pinia
使用。这里就不展开聊了。贴上完整代码:
// utils.js
export function hex2Rgb(color) {
color = color.replace('#', '')
const result = color.match(/../g)
for (let i = 0; i < 3; i++) {
result[i] = parseInt(result[i], 16)
}
return result
}
export function rgb2Hex(r, g, b) {
const hexs = [r.toString(16), g.toString(16), b.toString(16)]
for (let i = 0; i < 3; i++) {
if (hexs[i].length === 1) {
hexs[i] = '0' + hexs[i]
}
}
const result = '#' + hexs.join('')
return result
}
export function lighten(color, level) {
const rgb = hex2Rgb(color)
for (let i = 0; i < 3; i++) {
rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i])
}
const result = rgb2Hex(rgb[0], rgb[1], rgb[2])
return result
}
export function darken(color, level) {
const rgb = hex2Rgb(color)
for (let i = 0; i < 3; i++) {
rgb[i] = Math.floor(rgb[i] * (1 - level))
}
const result = rgb2Hex(rgb[0], rgb[1], rgb[2])
return result
}
// index.vue
<template>
<div class="container">
<el-button>Default</el-button>
<el-button v-for="item in types" :key="item" :type="item">{{ item }}</el-button>
<hr>
<el-radio-group v-model="radio" @change="radioChangeHandle">
<el-radio v-for="item in types" :key="item" :label="item" size="large">{{ item }}</el-radio>
</el-radio-group>
<br>
<el-color-picker v-model="color" @change="colorChangeHandle" color-format="hex" :show-alpha="false" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import { lighten, darken } from '@/utils'
const el = document.documentElement
const types = ref(['primary', 'success', 'info', 'warning', 'danger'])
const radio = ref('primary')
const color = ref(getComputedStyle(el).getPropertyValue(`--el-color-${radio.value}`))
const radioChangeHandle = () => {
const value = getComputedStyle(el).getPropertyValue(`--el-color-${radio.value}`)
color.value = value
}
const colorChangeHandle = (value) => {
el.style.setProperty(`--el-color-${radio.value}`, value)
for (let i = 1; i <= 9; i++) {
el.style.setProperty(`--el-color-${radio.value}-light-${ i }`, lighten(value, i / 10))
el.style.setProperty(`--el-color-${radio.value}-dark-${ i }`, darken(value, i / 10))
}
}
</script>
<style>
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -100%);
width: 50%;
text-align: center;
}
</style>
以上就是本次分享的内容,附上源码。
感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!
- 基于 Vue3 + Element-plus 管理后台基础功能框架 - 预览:http://admin.gumingchen.icu- Github:https://github.com/gmingchen/agile-admin- Gitee:https://gitee.com/shychen/agile-admin- 基础版后端:https://github.com/gmingchen/java-spring-boot-admin- 文档:http://admin.gumingchen.icu/doc/
- 基于 Vue3 + Element-plus + websocket 即时聊天系统 - 预览:http://im.gumingchen.icu- 代码:https://github.com/gmingchen/vue3-element-plus-im- 后端代码:https://github.com/gmingchen/java-im
- 基于 node 开发的后端服务:https://github.com/gmingchen/node-server
版权归原作者 拖孩 所有, 如有侵权,请联系我们删除。