前言

主题的切换研究过好久了,个人认为目前最好的两种实现:

  1. 原生css变量实现,性能好,但是不太兼容旧设备
  2. 利用预处理scss这种做一个主题类名,通过最上层类名变化从而改变嵌套的子类名的颜色,兼容性好,但是需要把所有的类都抽出来单独设置。

本着简单+性能的目标,我采用了第一种方案,这种方案也是大佬张鑫旭提供了,文章是:《link rel=alternate网站换肤功能最佳实现》

有兴趣弄的话可以先看看大佬的文章了解原理。

封装

主题的链接引入采用如下格式:

<!-- theme -->
<link href="<?php $this->options->themeUrl('/static/css/theme/light.css');?>" rel="stylesheet" type="text/css" title="light">
<link href="<?php $this->options->themeUrl('/static/css/theme/dark.css');?>" rel="alternate stylesheet" type="text/css" title="dark">

title用于区分是什么主题。

封装一个Theme类,使用懒汉单例模式

/** 主题map对象 */
interface ThemeMap {
  [key: string]: HTMLLinkElement;
}

class Theme {
  /** 静态实例 */
  private static interface: Theme;

  /** link元素数组 */
  private themeMap: ThemeMap = {};
  private activeTheme = "";

  private constructor() {
    const linkList = Array.from(document.querySelectorAll<HTMLLinkElement>('link[type="text/css"][title]'));

    linkList.forEach((link) => {
      const title = link.getAttribute("title");
      if (!title) return;
      const rel = link.getAttribute("rel");

      this.themeMap[title] = link;
      if (rel && !rel.includes("alternate")) {
        this.activeTheme = title;
      }
    });

    const localTheme = localStorage.getItem("theme");
    if (localTheme && localTheme !== this.activeTheme) {
      this.switchTheme(localTheme);
    }
  }

  /** 获取当前主题 */
  public getActiveTheme() {
    return this.activeTheme;
  }

  /** 切换指定主题 */
  public switchTheme(theme: string) {
    if (theme === this.activeTheme) return;

    Object.keys(this.themeMap).forEach((key) => {
      const link = this.themeMap[key];
      link.disabled = true; // 先禁用,不管是否启用
      if (key === theme) link.disabled = false; // 启用指定主题
    });

    this.activeTheme = theme;
    localStorage.setItem("theme", theme);
  }

  /** 获取主题实例 */
  public static getInterface() {
    if (!Theme.interface) {
      Theme.interface = new Theme();
    }
    return Theme.interface;
  }
}

export default Theme;

使用

import Theme from "@/utils/theme";

const themeInterface = Theme.getInterface();
themeInterface.switchTheme("dark");

做的比较简单,因为业务上用不到其他的,如果从安全的角度想,我们是不是需要验证切换的主题是不是合法的主题名呢,以及缓存的主题是否也需要判断一下,如果不合法手动删除等,但是我就不想这么麻烦了。

从开发的角度怎么说呢,不要过度的设想不存在的场景,加快开发进度才是正事。

分类: TypeScript 标签: typechoTypeScript主题切换themecss变量

评论

暂无评论数据

暂无评论数据

目录