vue-worker的使用,及element ui动态设置任意主题色

思路

获取document中所有的style标签,正则匹配替换里面含有主题色的字符串,并生成新的字符串append到body中,起到覆盖样式的作用

问题和解决

当样式字符串比较多时,正则匹配与替换这步操作耗时比较多,会阻塞当前页面,此时使用web-worker创建线程来解决

具体代码

1 安装js-cookie vue-worker
2 element-variables.scss
项目默认的自定义主题色, :export暴露主题色变量

/* 改变主题色变量 */
$--color-primary: #409EFF;

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

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

:export {
    color_primary:$--color-primary
}

3 change_theme.js
使用vue-worker创建web-worker线程, 匹配所有style标签的innerText, 然后循环匹配含有element主题色的样式块,例如....a{color:#409EFF;font-size:14px}.b{color:red}...中只匹配.a{color:#409EFF;font-size:14px}, 之后将匹配到的字符串进行replace操作,替换新的颜色主题,生成新的style插入或替换到body中,覆盖之前的代码,最后将新的主题色存于cookie
注意: web-worker中不能操作document和window对象,所以web-worker线程中只操作字符串

import Cookies from "js-cookie";
import variables from "@/assets/sass/element.variables.scss"; //element默认主题色

import VueWorker from "vue-worker"; //封装的web-worker插件
import Vue from "vue";

Vue.use(VueWorker);

const theme_color = variables.color_primary;
export default class Theme extends Vue {
  constructor(color) {
    super(color);
    this.worker = "";  
    this.init_color = color;  //类创建时接受的初始主题色

    if (color && theme_color != color) {  //若初始主题色与element主题色不同,执行换肤操作
      this.init_color = theme_color;
      this.set_stylestr(color);
    }
  }

  create_color_worker() { //创建webworker线程, 生成新的style字符串
    this.worker = this.$worker.create([
      {
        message: "filter_style_text",
        func(stylearr, dcolor_regexp, newrggexp, newcolor) {
          var newStyle = "";
          stylearr.forEach((i, k) => {  //样式字符串循环匹配含有主题色的样式字符串,并替换新的字符串
            var match = "";

            while ((match = dcolor_regexp.exec(i)) != null) {
              newStyle += match[0].replace(newrggexp, newcolor);
            }
          });

          return newStyle;
        },
      },
    ]);
  }

  set_stylestr(newcolor) { //换肤操作
    
    this.$message({         
      message: "正在替换主题",
      iconClass: "el-icon-loading",
      duration: 0,
    });

    var stylearr = [];   
    Array.prototype.slice
      .call(document.querySelectorAll("style"))
      .forEach((i) => {
        stylearr.push(i.innerText);
      });

    this.create_color_worker(); 

    var dcolor_regexp = new RegExp(   //初始颜色样式的正则
      "[^}]+{[^}]+" + this.init_color + "[^}]*}",
      "ig"
    );

    var newrggexp = new RegExp(this.init_color, "ig"); //替换颜色的正则

    this.worker
      .postMessage("filter_style_text", [
        stylearr,
        dcolor_regexp,
        newrggexp,
        newcolor,
      ])
      .then((newStyle) => {
        let styleTag = document.getElementById("fugai_theme");
        if (!styleTag) {
          styleTag = document.createElement("style");
          styleTag.setAttribute("id", "fugai_theme");
          document.body.appendChild(styleTag);
        }
        styleTag.innerText = newStyle;

        Cookies.set("theme_color", newcolor);
        this.worker = null;  //清除webworker实例

        this.$message.closeAll();
        this.$message({
          message: "替换成功",
          type: "success",
        });
      
      });
  }
}

4 main.js 部分代码
项目初始时创建Theme对象,传入的颜色为之前换肤的颜色

import "@/assets/sass/element.variables.scss";
import Theme from "@/util/change_theme.js"
var themecolor = Cookies.get("theme_color")
Vue.prototype.$theme=new Theme( themecolor );

5 换肤操作
在需要的页面中调用this.$theme..set_stylestr("blue"),此处为替换蓝色主题

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值