动态主题

动态主题

动态样式文件

改变皮肤 link 元素的 href 地址。例如:

<link id="skinLink" href="skin-default.css" rel="stylesheet" type="text/css">

换皮肤的时候 JS 改变 href 属性值:

skinLink.href = "skin-red.css";

webpack-theme-color-replacer

m-fe-rtw, 基于 React & TypeScript & Webpack 的微前端复杂应用项目模板中,我们使用了 webpack-theme-color-replacer。webpack-theme-color-replacer 在 Webpack 构建时,在 emit 事件(准备写入 dist 结果文件时)中,将即将生成的所有 CSS 文件的内容中 带有指定颜色的 CSS 规则单独提取出来,再合并为一个 theme-colors.css 输出文件。然后在切换主题色时,下载这个文件,并替换为需要的颜色,应用到页面上。这样,下载的样式中就只包含颜色相关的 CSS 规则,文件较小;同时它已经包含了项目中所有的 CSS 中的指定颜色样式,一次下载全部颜色样式都搞定。首先我们添加替换插件:

new ThemeColorReplacer({
  fileName: "theme-colors-[contenthash:8].css",
  matchColors: getAntdSerials("#5d4bff"), // 主色系列
  // 改变样式选择器,解决样式覆盖问题
  changeSelector(selector) {
    switch (selector) {
      case ".ant-calendar-today .ant-calendar-date":
        return ":not(.ant-calendar-selected-date)" + selector;
      case ".ant-btn:focus,.ant-btn:hover":
        return ".ant-btn:focus:not(.ant-btn-primary),.ant-btn:hover:not(.ant-btn-primary)";
      case ".ant-btn.active,.ant-btn:active":
        return ".ant-btn.active:not(.ant-btn-primary),.ant-btn:active:not(.ant-btn-primary)";
      default:
        return selector;
    }
  },
});

该插件会生成一个 CSS 文件:

.el-tag {
  color: #f67a17;
}

.el-tag.is-hit {
  border-color: #f67a17;
}

并且在 Runtime 中插入如下代码:

window.__theme_COLOR_cfg = {
  url: "theme-colors-05d50e3a.css",
  colors: [
    "#5d4bff",
    // ...
  ],
};

这样就能获得到某个颜色对应的元素 ID,在执行颜色切换的时候,直接调用 Client 的 client.changer.changeColor(options, Promise); changeColor 方法:

// 首先判断 theme-colors.css 是否已经被插入到了文档,如果未插入则执行拉取然后再插入
setCssTo(elStyle, elStyle.innerText);

// 执行 Style 内置替换
function setCssTo(elStyle, cssText) {
  cssText = _this.replaceCssText(cssText, oldColors, newColors);
  elStyle.color = newColors.join("|");
  elStyle.innerText = cssText;
  theme_COLOR_config.colors = newColors;
}

// 直接全局替换样式方式进行切换
function replaceCssText(cssText, oldColors, newColors) {
  oldColors.forEach(function (color, t) {
    cssText = cssText.replace(
      new RegExp(color.replace(/,/g, ",\\s*"), "ig"),
      newColors[t]
    ); // 255, 255,3
  });
  return cssText;
}

alternate

<link href="reset.css" rel="stylesheet" type="text/css">

<link href="default.css" rel="stylesheet" type="text/css" title="默认">

<link href="red.css" rel="alternate stylesheet" type="text/css" title="红色">

<link href="green.css" rel="alternate stylesheet" type="text/css" title="绿色">

上面 4 个 <link> 元素,共出现了 3 中不同性质的 CSS 样式文件加载:

  • 没有 title 属性,rel 属性值仅仅是 stylesheet 的 <link> 无论如何都会加载并渲染,如 reset.css;

  • 有 title 属性,rel 属性值仅仅是 stylesheet 的作为默认样式 CSS 文件加载并渲染,如 default.css;

  • 有 title 属性,rel 属性值同时包含 alternate stylesheet 的作为备选样式 CSS 文件加载,默认不渲染,如 red.css 和 green.css;

这里有个非常有趣的特性,那就是 rel=“stylesheet"的如果有 title 属性并有值,性质上就变成了一个可以控制其渲染或者不渲染的特殊元素了。

使用 JavaScript 代码修改元素 DOM 对象的 disabled 值为 false,可以让默认不渲染的 CSS 开始渲染。注意,必须是 DOM 元素对象的 disabled 属性,而不是 HTML 元素的 disabled 属性,元素是没有 disabled 属性的。

// 渲染 red.css 这个皮肤
document.querySelector('link[href="red.css"]').disabled = false;

全局变量

Links

上一页