【VUE】ElementPlus之动态主题色调切换(Vue3 + Element Plus+Scss + Pinia)

前言

关于ElementPlus的基础主题色自定义可以参阅《【VUE】ElementPlus之自定义主题样式和命名空间

有了上面基础的了解,我们知道ElementPlus的主题色调是基于CSS3变量特性进行全局控制的,

那么接下来我们也基于CSS3变量来实现主题色调的动态切换效果;

主要控制的色调类型有:primarysuccesswarningdangererrorinfo

针对这六个色调类型分别进行035789级的渐变色定制

以下是默认情况下的主题颜色定义:

接下来,我们基于以下环境来实操下:

  • vue: ^3.3.4
  • vite: ^4.4.11
  • sass: ^1.58.3
  • element-plus: ^2.3.4
  • pinia: ^2.1.7

实现

默认主题色下的按钮组件色调:

预想效果:

在实现具体交互之前,我们先准备几个辅助小工具

颜色状态管理器

既然是动态切换,那么我们就需要一个容器来记录当下的一些色调信息,便于整体性的调整

以下仅抛个砖,具体业务调整根据自己需要来哈~

javascript 复制代码
import { defineStore } from "pinia";
import ColorUnit from "@/unit/ColorUnit";

export const useColorStore = defineStore("color", () => {
  function setThemeColor(colorMap) {
    let _namespace = "el";
    colorMap.forEach((colorItem) => {
      setPropertyColor(`--${_namespace}-color-${colorItem[0]}`, colorItem[1]);
      themeColorGradient(`--${_namespace}-color-${colorItem[0]}-light-#level#`,"lighten",colorItem[1]);
      setPropertyColor(`--${_namespace}-color-${colorItem[0]}-dark-2`,colorItem[1],"darken");
      // themeColorGradient(`--${_namespace}-color-${colorItem[0]}-dark-#level#`,"darken",colorItem[1]);
    });
  }

  /**
   * 将css3变量设置到document中方便全局调用
   */
  function setPropertyColor(varName, color, funName, level) {
    level = level ? level : 0;
    funName = funName ? funName : "lighten";
    document.documentElement.style.setProperty(
      varName,
      ColorUnit[funName](color, level / 10)
    );
  }

  /**
   * 生成主色的其余渐变色并修改对应CSS3变量值
   */
  function themeColorGradient(varName, funName, themeColor, themeLevel) {
    themeColor = themeColor ? themeColor : '#409eff';
    themeLevel = themeLevel ? themeLevel : [3, 5, 7, 8, 9];

    themeLevel.forEach(function (level) {
      setPropertyColor(
        varName.replace("#level#", level),
        themeColor,
        funName,
        level
      );
    });
  }

  return {
    setThemeColor,
  };
});

颜色编码生成工具

根据前言描述,我们得知,需要根据一个十六进制的色值,生成其余的渐变色值出来,手动配置的话就太麻烦了

所以我们先来封装一个ColorUnit工具来辅助我们进行色调的配置

javascript 复制代码
// file: src/unit/ColorUnit.js
// 代码载取来至:https://gitee.com/lolicode/scui/blob/master/src/utils/color.js
export default {
	//hex颜色转rgb颜色
	HexToRgb(str) {
		str = str.replace("#", "")
		var hxs = str.match(/../g)
		for (var i = 0; i < 3; i++) hxs[i] = parseInt(hxs[i], 16)
		return hxs
	},
	//rgb颜色转hex颜色
	RgbToHex(a, b, c) {
		var hexs = [a.toString(16), b.toString(16), c.toString(16)]
		for (var i = 0; i < 3; i++) {
			if (hexs[i].length == 1) hexs[i] = "0" + hexs[i]
		}
		return "#" + hexs.join("");
	},
	//加深
	darken(color, level) {
		var rgbc = this.HexToRgb(color)
		for (var i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level))
		return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2])
	},
	//变淡
	lighten(color, level) {
		var rgbc = this.HexToRgb(color)
		for (var i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i])
		return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2])
	}
}

整合

有了上面俩个帮手,现在整合起来的具体应用

template部分

xml 复制代码
<template>
  <main>
    <el-row style="margin-bottom: 15px">
      <div class="demo-color-warp">
        <div class="demo-color-box" v-for="(item, key) in _theme" :key="key"
             @click="setThemeColor(item.color, item.label)"
             :style="{'--color':item.color[0][1]}">
          <span class="demo-color__label">{{ item.label }}</span>
          <span class="demo-color__value">{{ item.color[0][0] }}</span>
          <span class="demo-color__value">{{ item.color[0][1] }}</span>
          <ul class="demo-color__list">
            <template v-for="(colorItem, colorKey) in item.color" :key="colorKey">
              <li v-if="colorKey>0" :style="{'--color':colorItem[1]}">
<!--                <span>{{ colorItem[0] }}</span>-->
<!--                <span>{{ colorItem[1] }}</span>-->
              </li>
            </template>
          </ul>
        </div>
      </div>
      <span>当前主题:{{ themeName }}</span>
    </el-row>

    <el-row class="mb-4">
      <el-button>Default</el-button>
      <el-button type="primary">Primary</el-button>
      <el-button type="success">Success</el-button>
      <el-button type="info">Info</el-button>
      <el-button type="warning">Warning</el-button>
      <el-button type="danger">Danger</el-button>
    </el-row>

    <el-row class="mb-4">
      <el-button plain>Plain</el-button>
      <el-button type="primary" plain>Primary</el-button>
      <el-button type="success" plain>Success</el-button>
      <el-button type="info" plain>Info</el-button>
      <el-button type="warning" plain>Warning</el-button>
      <el-button type="danger" plain>Danger</el-button>
    </el-row>

    <el-row class="mb-4">
      <el-button round>Round</el-button>
      <el-button type="primary" round>Primary</el-button>
      <el-button type="success" round>Success</el-button>
      <el-button type="info" round>Info</el-button>
      <el-button type="warning" round>Warning</el-button>
      <el-button type="danger" round>Danger</el-button>
    </el-row>

    <el-row>
      <el-button :icon="Search" circle />
      <el-button type="primary" :icon="Edit" circle />
      <el-button type="success" :icon="Check" circle />
      <el-button type="info" :icon="Message" circle />
      <el-button type="warning" :icon="Star" circle />
      <el-button type="danger" :icon="Delete" circle />
    </el-row>
  </main>
</template>

script部分

javascript 复制代码
<script setup>
import {ref} from "vue"
import { useColorStore } from "@/stores/color";
// ...
const themeName = ref('默认主题');
const colorStore = useColorStore();
// ...
let _theme = [
  {label:'默认主题', color:[["primary", "#409EFF"], ["success", "#67C23A"], ["warning", "#E6A23C"], ["danger", "#F56C6C"], ["error", "#F56C6C"], ["info", "#909399"]]},
  {label:'自定义主题1', color:[["primary", "#1984f3"], ["success", "#55DE12"], ["warning", "#EA9412"], ["danger", "#E12020"], ["error", "#E12020"], ["info", "#209399"]]},
  {label:'自定义主题2', color:[["primary", "#0A4680"], ["success", "#276409"], ["warning", "#815410"], ["danger", "#931d1d"], ["error", "#931D1D"], ["info", "#454A55"]]},
];
// ...
function setThemeColor(colorMap, label) {
  themeName.value = label;
  colorStore.setThemeColor(colorMap);
}
// ...
</script>
相关推荐
花花鱼1 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09334 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang135826 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning26 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人36 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱00137 分钟前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
子非鱼9211 小时前
【Ajax】跨域
javascript·ajax·cors·jsonp
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程1 小时前
【前端基础】CSS基础
前端·css