基于elementui的主题色改变和全网站色彩切换

主题色切换

什么是主题色切换,所谓的主题色切换就是我们通过自定义的方式去修改elementUI原有的主题色,以达到我们业务所要使用的多(单)色彩切换.

静态切换

elementui 采用的是scss进行实现的样式 我们的项目也使用的是scss 因此我们在项目中创建一个element-variables.scss文件存放我们修改的主题色

/* 改变主题色变量 */
$--color-primary: 自定义的主题色;

/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';

@import "~element-ui/packages/theme-chalk/src/index";

在项目的入口文件中引用定义的文件

import Vue from 'vue'
import Element from 'element-ui'
import './element-variables.scss'
Vue.use(Element)

如果项目中没有使用scss的话则参考elementui官网进行配置
element-ui

动态切换

动态切换则是我们通过element-ui的颜色选择器,和获取远端element-ui主题样式,通过标签匹配替换的方式进行改变的。
封装的组件

<template>
  <el-color-picker v-model="theme" />
</template>
<script>
  const version = require("element-ui/package.json").version;
  const ORIGINAL_THEME = "#409EFF";
  export default {
    name:"theme",
    props: {
      //接收初始化传递过来的颜色
      color: String,
    },
    data() {
      return {
      //远端请求回来的css数据
        chalk: "",
        //绑定的主题色
        theme: "",
      };
    },
    computed: {
      //默认主题色
      defaultTheme() {
        return this.color;
      },
    },
    watch: {
      defaultTheme: {
        handler: function (val, oldVal) {
          //将默认主题色赋值给颜色选择器
          this.theme = val;
        },
        immediate: true,
      },
      //监听绑定的颜色的变化
      async theme(val) {
        const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
        if (typeof val !== "string") return;
        //新的主题色相关
        const themeCluster = this.getThemeCluster(val.replace("#", ""));
        //旧的主题相关色
        const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
        //如果主题的样式文件不存在则从远端重新获取,否则直接加载新的样式

          await this.getCSSString();

        this.getHandler(themeCluster);
        const styles = [].slice
          .call(document.querySelectorAll("style"))
          .filter((style) => {
            const text = style.innerText;
            return (
              new RegExp(oldVal, "i").test(text) && !/Chalk Variables/.test(text)
            );
          });
        console.log(styles,'wewe222')
        styles.forEach((style) => {
          const { innerText } = style;
          if (typeof innerText !== "string") return;
          style.innerText = this.updateStyle(
            innerText,
            originalCluster,
            themeCluster
          );
        });
        this.$emit("color-update", val);
      },
    },
    methods: {
      // 修改element-ui主题样式表颜色
      updateStyle(style, oldCluster, newCluster) {
        let newStyle = style;
        oldCluster.forEach((color, index) => {
          newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
        });
        return newStyle;
      },
      // 生成新的样式表
      getHandler(themeCluster) {
        //获取源style
        const originalCluster = this.getThemeCluster(
          ORIGINAL_THEME.replace("#", "")
        );
        const newStyle = this.updateStyle(
          this.chalk,
          originalCluster,
          themeCluster
        );
        let styleTag = document.getElementById("chalk-style");
        if (!styleTag) {
          styleTag = document.createElement("style");
          styleTag.setAttribute("id", "chalk-style");
          document.head.appendChild(styleTag);
        }
        styleTag.innerText = newStyle;
      },
      // 获取element-ui主题样式
      getCSSString() {
        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
        return new Promise((resolve) => {
          const xhr = new XMLHttpRequest();
          xhr.onreadystatechange = () => {
            if (xhr.readyState === 4 && xhr.status === 200) {
              //获取到的element的样式
              this.chalk = xhr.responseText.replace(/@font-face{[^}]+}/, "");
              resolve();
            }
          };
          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));
        console.log(clusters,'wewe')
        return clusters;
      },
    },
  };
</script>

全网站色彩切换

思路:全网站的色彩切换 其根本的原理在于 在body上去添加不同的class 同时通过class名匹配的方式去修改 其他内容的颜色

//页面初次加载的时候我们默认一个class
localStorage.setItem('theme',"default")

主题切换

handleChangeTheme(theme){
//主题切换
let theme=theme?theme:"default"
localStorage.setItem('theme',theme)
dcoumnet.getElementByTagName('body')[0].className='theme'
/*在加载的scss文件中去定义每个主题下对相应的颜色变化*/
.logo{
color:"pink" /*默认主题下是粉色*/
}
.dask{
.logo{
 color:"white"/*黑色主题下是白色*/
}
}

这样就实现了全网站的色彩切换,有个不好的地方就是这种可能就需要我们写两组或者多组的样式 实现样式,主题色的切换。
接下来探索更优的主题色彩切换方案

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值