利用typescript实现原生css变量的主题切换功能类
前言
主题的切换研究过好久了,个人认为目前最好的两种实现:
- 原生css变量实现,性能好,但是不太兼容旧设备
- 利用预处理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");
做的比较简单,因为业务上用不到其他的,如果从安全的角度想,我们是不是需要验证切换的主题是不是合法的主题名呢,以及缓存的主题是否也需要判断一下,如果不合法手动删除等,但是我就不想这么麻烦了。
从开发的角度怎么说呢,不要过度的设想不存在的场景,加快开发进度才是正事。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据