element-plus 动态自定义主题颜色

发布时间 2023-11-09 09:43:41作者: 7c89

颜色的HEX格式

颜色的HEX格式是#+六位数字/字母,其中六位数字/字母是一种十六进制的表达方式。这六位分别两个一组,从左到右分别表示绿00表示最小,十进制是0FF表示最大,十进制是255。通俗点讲,某个颜色的数值越大,包含这个颜色就越多。如:#000000-黑色、#FFFFFF-白色、#FF0000-红色、#00FF00-绿色、#0000FF-蓝色。

HEX格式颜色变亮、变暗

通过上文的介绍,我们可以知道Elementhover颜色变亮了,即颜色的数值变大了,那我们只要对要修改的颜色数值变大即可。那就需要用到以下的方法:

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>