发布于 2026-01-06 0 阅读
0

Angular 6:无需库即可实现动态主题

Angular 6:无需库即可实现动态主题

主题化的概念由来已久。让用户能够选择产品的外观和风格具有巨大的价值——它能创造更本地化的体验,并减少开发人员的维护时间。

Tumblr

我们如何在Angular应用程序中创建类似的功能?

为什么单靠 Sass 是行不通的

虽然 Sass 变量可以用来创建预设的主题体验,但最大的缺点是它无法被 JavaScript 操作。我们需要用 JavaScript 来动态地改变变量的值!

为什么单靠材料是行不通的

自从 Angular Material 发布以来,开发者们纷纷涌向这个库,利用其可重用的组件(更不用说其内置的辅助功能了)。

Material Design 自带主题功能,但由于以下两个原因,该功能可能无法正常工作:

  1. Material 默认自带一套针对无障碍访问优化的调色板。如果需要生成更多颜色,则需要将其传递给 Material 的 mat-palette mixin,或者使用第三方工具创建一个新的主题文件。这样做会引入外部依赖项,并限制在不修改代码的情况下切换主题的能力。

  2. 虽然 Material 是个不错的选择,但并非所有人都想使用它!许多开发者不希望为了使用组件而导入整个库,而是选择创建自己的组件。

解决方案?Sass + CSS 变量!

如果您从未用过原生 CSS 自定义属性(我称之为变量),这里有一篇很棒的文章(链接在此)可以帮助您入门。这种方法之所以有效,是因为 CSS 变量可以被 JavaScript 操作!通过这种方式,您可以使用表单将 CSS 变量传递给 Sass 映射,从而在整个应用程序中使用该映射。

让我们看看!

执行

此实现方式:

  • 未使用任何外部库
  • 允许多个组件通过表单动态更改样式。
  • 将表单保存为可保存到数据库或本地存储的对象。
  • 能够将外部对象加载为预加载或预设样式

演示链接:https://native-theming-form-medium.stackblitz.io/

Stackblitz 链接:https://stackblitz.com/edit/native-theming-form-medium

魔法

该方法的核心原理是将 Sass 映射和 CSS 变量结合起来。

在 theme.scss 文件中,默认值被设置并传递给一个 Sass 映射。

theme.scss

// default colors
.theme-wrapper {
    --cardColor: #CCC;
    --cardBackground: #FFF;
    --buttonColor: #FFF;
    --buttonBackground: #FFF;
    --navColor: #FFF;
    --navBackground: #FFF;
    --footerColor: #FFF;
    --footerBackground: #FFF;
    --footerAlignment: left;
}
// pass variables into a sass map
$variables: (
    --cardColor: var(--cardColor),
    --cardBackground: var(--cardBackground),
    --buttonColor: var(--buttonColor),
    --buttonBackground: var(--buttonBackground),
    --navColor: var(--navColor),
    --navBackground: var(--navBackground),
    --footerColor: var(--footerColor),
    --footerBackground: var(--footerBackground),
    --footerAlignment: var(--footerAlignment)
);
Enter fullscreen mode Exit fullscreen mode

创建了一个函数,用于从全局 Sass 映射中返回原生 CSS 变量。

function.scss

@function var($variable) {
    @return map-get($variables, $variable);
}
Enter fullscreen mode Exit fullscreen mode

现在,这些组件可以读取这两个文件,以存储一个在表单重新提交时会发生变化的动态变量。

card.component.scss

@import '../../theme';
@import '../../functions';
.card {
    background-color: var(--cardBackground);
    color: var(--cardColor);
}
Enter fullscreen mode Exit fullscreen mode

卡片的背景颜色现在是 #FFFFFF,文字颜色是 #CCCCCC

但是我们如何改变这些价值观呢?

通过主题选择器组件!

在我们的 theme-picker.component.html 文件中,我们使用带有 ngModel 的模板表单来创建一个具有唯一键(样式)和值(输入)的对象。然后,该对象被传递给 TypeScript 文件,该文件会动态地覆盖该变量。

主题选择器组件.ts

// searching the entire page for css variables
private themeWrapper = document.querySelector('body');
onSubmit(form) {
    this.globalOverride(form.value);
}
globalOverride(stylesheet) {
    if (stylesheet.globalNavColor) {
        this.themeWrapper.style.setProperty('--navColor',     stylesheet.globalNavColor);
    }
...
    if (stylesheet.globalButtonColor) {
        this.themeWrapper.style.setProperty('--buttonColor',     stylesheet.globalButtonColor);
    }
}
Enter fullscreen mode Exit fullscreen mode

globalOverride 函数会检查该特定变量是否存在值,然后将每个 CSS 变量替换为新输入的值。

Violá!

这段代码可以进一步优化以适应规模(使用预设样式对象,在提交时保存/发布样式),所以请随意尝试!

文章来源:https://dev.to/adamaso/angular-6-dynamic-themes-without-a-library-2e9c