在 Angular 中实现浅色/深色模式
浅色/深色模式切换是当今 Web 应用程序中非常常见的功能。对于最终用户来说,这个功能看起来可能很简单,但要在 Web 应用程序中正确实现它,却需要一些额外的工作。
本文将重点介绍使用 Angular 和现代 CSS 功能实现暗黑模式的最直接方法之一。
此外,作为额外福利,我还会分享一个包含一些相关附加功能的 Angular 项目示例。
让我们开始吧!
为什么在Angular中会遇到(一些)困难?
从宏观层面来说,实现暗黑模式需要一个 CSS-in-JS 库,以便可以使用 JavaScript 来操作 CSS。像 React 这样的 Web 库提供了极大的灵活性,可以集成任何 CSS-in-JS 库,从而帮助开发者轻松实现暗黑模式。
但Angular有所不同。作为一个框架,大部分功能都由框架本身处理,因此修改底层库的方式非常有限。此外,Angular默认的视图封装机制使得从外部修改组件样式变得非常困难。(显然,这正是其设计目的。)
高层架构
CSS 变量在其中扮演着重要角色。基本上,你可以根据 DOM 中的某个属性(通常是 CSS 元素class)来分配一些 CSS 变量body。然后,你可以使用 JavaScript 更改该属性,从而使 CSS 变量也随之改变,进而影响子组件的样式。
我将用图表来解释这一点。
- 首先,根据 body 元素中的类定义并分配一组 CSS 变量。
- 这些 CSS 变量用于组件样式中
- 更新 body 元素中的类名以更改 CSS 变量赋值。最终也会影响组件样式。
让我们开始编写代码吧!
首先,让我们在全局styles.scss文件中定义一些样式变量。(本例中我使用的是 SCSS,但这完全是可选的。)
$bgColor_light: white;
$bgColor_dark: black;
$textColor_light: black;
$textColor_dark: white;
$borderColor_light: black;
$borderColor_dark: white;
// mixin that enables css variables in light mode
@mixin lighten() {
--bgColor: #{$bgColor_light};
--textColor: #{$textColor_light};
--borderColor: #{$borderColor_light};
}
// mixin that enables css variables in dark mode
@mixin darken() {
--bgColor: #{$bgColor_dark};
--textColor: #{$textColor_dark};
--borderColor: #{$borderColor_dark};
}
现在我们需要以条件方式调用上述 mixin。我们使用 body 元素中的 CSS 类名来确定要调用哪个 mixin。
body.dark {
@include darken();
}
body.light {
@include lighten();
}
现在你可以使用这些 CSS 变量来设置 Angular 组件的样式。
main {
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: var(--bgColor);
color: var(--textColor);
}
请确保不要在组件中直接使用 SCSS 变量,因为这些变量一旦定义就不会改变。
最后,让我们创建一个 Angular 组件,以编程方式更新元素中的 CSS 类document.body。
/**
* Function that toggles the current mode
* Exposed publicly
*/
toggleMode() {
this.document.body.classList.toggle(Mode.LIGHT);
this.document.body.classList.toggle(Mode.DARK);
if (this.currentMode === Mode.LIGHT) {
this.updateCurrentMode(Mode.DARK);
} else {
this.updateCurrentMode(Mode.LIGHT);
}
}
就这些。非常简单明了。
检查用户设备偏好设置
某些设备允许用户在系统设置中设置设备主题。因此,我们的 Web 应用程序必须能够兼容这些设备主题,并正确加载相应的模式。
您可以使用以下@media查询轻松验证这一点
@media (prefers-color-scheme: dark) {
...
}
但是,我们将在您的 Javascript 逻辑中使用它。
/**
- Init function that update the application based on the initial mode value
- Flow as below
- 1 - If there is a saved mode in the browser - use this as the initial value
- 2 - If there is no saved mode, Check for the preferred device theme
- 3 - If device theme is dark, set the init value to
dark
- 4 - Else set the default value to
light
*/
private init() {
const deviceMode = window.matchMedia("(prefers-color-scheme: dark)");
let initMode = this.modeStorage.get();
if (!initMode) {
deviceMode.matches ? (initMode = Mode.DARK) : (initMode = Mode.LIGHT);
}
this.updateCurrentMode(initMode);
this.document.body.classList.add(this.currentMode);
}
参考项目
正如我承诺的那样,我将分享我创建的示例项目,以演示上述实现以及一些其他功能,例如:
- 浅色/深色模式切换按钮组件
- 可用于实现自定义切换组件的 Angular 服务
- 通过本地存储实现持久化(也能够编写其他持久化方法,例如会话存储)
- 基于 RxJS Observable 的模式切换监听器
- SCSS 支持 CSS 变量
- 根据设备主题偏好加载初始模式
- 无需其他库
- 文档齐全的代码
Github:Angular Light / Dark App
您可以在文件中找到所有开发信息README.md。
今天就到这里。欢迎分享您的反馈意见。感谢阅读。
文章来源:https://dev.to/pahanperera/implement-light-dark-mode-in-angular-42ff

