• 目录

    介绍

    灵感

    设计

    实现

    1. 切换样式表

    2. CSS变量

    3. 主题切换

    4. 将按钮链接到开关

    编码

    主题库

    1. ThemeToggle组件

    2. ThemeService(核心)

    3a 主题组件方法

    3b CSS类更改方法

    测试主题切换

    Chrome/Edge

    FireFox

    Opera

    总结


  • 下载源代码 - 438.7 KB

介绍

本文讨论了从需求到实施的过程,以了解主题支持的实施和使用方式和方式。代码片段用于帮助撰写文章,而不是完整的代码转储。所有代码和示例项目都包含在下载中,以供进一步研究和试用。

本文假定您对Blazor有基本的了解,并提供指向您可能需要进一步信息和/或解释的各种外部资源的链接。

灵感

我想要一个具有现代动画效果的主题切换按钮。我喜欢Google Fonts网站上的按钮,但我是后端开发人员,而不是UI网页设计师。这是他们的按钮。

(点击上图查看主题切换的工作原理)

下面是集成到此Blazor解决方案中的Kevin按钮。

(点击上图查看主题切换的工作原理)

设计

这个概念是:

  1. 最少的代码——完全包装或对自定义实现开放
  2. 开放式设计可与任何定制代码或CSS框架(如Bootstrap、Tailwind等)一起使用。
  3. 可跨多个项目重用
  4. 如果不可避免,最少的JavaScript
  5. 最新的Blazor和CSS3编码技术

实现

对于本文,使用了两种不同的主题切换方法:

1. 切换样式表

允许将主题明显分离到单独的文件中。这允许从Bootswatch等第三方网站下载主题。我在本文中使用了他们的Darkly(深色主题)和Flatly(浅色主题)。这是一种较旧的主题切换技术。

实现主题支持的最佳位置是尽可能靠近DOM的顶部。这是在MainLayout.razor中完成的。

对于样式表切换,我们需要更改页面head部分。为此,我们使用MainLayout.razor中的HeadContent组件:

<HeadContent>/* elements go here */
</HeadContent>

使用HeadContent组件时,顺序很重要。该组件将内容添加到页面head底部。

CSS样式表通常添加到index.html文件中。但是,为了切换样式表,我们从index.html 中删除颜色样式,并将文件放在MainLayout.razor文件中的<HeadContent>块中:

<HeadContent><Themes><DarkMode><link href="css/bootstrap/darkly.min.css" rel="stylesheet" /></DarkMode><LightMode><link href="css/bootstrap/flatly.min.css" rel="stylesheet" /></LightMode></Themes><link href="css/app.css" rel="stylesheet" /><link href="ThemeByStylesheetDemo.styles.css" rel="stylesheet" />
</HeadContent>

应用程序CSS无需更改,因为每个主题文件中都应用了相同的CSS规则。这种方法侵入性最小,但是在切换主题时,浏览器刷新时页面可能会轻微闪烁。

2. CSS变量

CSS变量,也称为自定义属性,是当今网站中使用的现代推荐技术。像Open Props这样的CSS框架广泛使用CSS变量

主题切换是使用CSS完成的。在我们的例子中,我们默认为light模式,并添加一个CSS类名dark来切换模式。CSS标记看起来像:

:root {/* Light theme */--background: #fff;--font-color: #000;--font-color-2: #fff;--highlight: #f7f7f7;--highlight-2: #95a6a6;--link: #0366d6;
}.dark {/* dark theme */--background: #222;--font-color: #fff;--font-color-2: #fff;--highlight: #393939;--highlight-2: #444444;--link: #3ca4ff;
}

使用CSS变量:

.page {background-color: var(--background);color: var(--font-color);
}

此方法确实需要使用CSS变量,因此需要更改现有样式表代码和内联样式规则,但好处是浏览器更新时不会闪烁。另一个好处是您现在使用共享变量和您的css更易于维护。

3. 主题切换

上面的动画示例,如谷歌字体网站,有一个用于手动切换的按钮。还有一个媒体查询,用于通过操作系统或网络浏览器检测用户更改。

所以通常在CSS中,我们会使用prefers-color-scheme媒体查询。

为此,我们需要监听change事件。Blazor目前无法直接监听媒体查询,因此我们需要使用一些带有回调的JavaScript到Blazor中。

这是JavaScript:

function createThemeListener(dotNetRef) {window.matchMedia("(prefers-color-scheme: dark)").addListener(e => dotNetRef.invokeMethodAsync("DarkModeStateChanged", e.matches));

Blazor中的初始化程序,我们通过回调传递对我们类的引用:

_jsRuntime = jsRuntime;
_moduleTask = new(() => jsRuntime.ModuleFactory(ScriptFile));IJSObjectReference module = await _moduleTask!.Value;
DotNetInstance = DotNetObjectReference.Create(this);

以及对Blazor的JavaScript事件的回调:

[JSInvokable]
public async Task DarkModeStateChanged(bool state)=> await SetDarkModeAsync(state).ConfigureAwait(false);

javascript代码位于库中。使用最新版本的Blazor,可以包含javascript文件,而无需手动将其添加到index.html文件中。为此,我们export  javascript 函数。编译器看到了这一点,并为我们包含了javascript。所以更新后的javascript看起来像这样:

export function isDarkTheme() {return  window.matchMedia("(prefers-color-scheme: dark)").matches;
}export function createThemeListener(dotNetRef) {window.matchMedia("(prefers-color-scheme: dark)").addListener(e => dotNetRef.invokeMethodAsync("DarkModeStateChanged", e.matches));
}export function getLocalStorage(key) {return localStorage[key];
}
export function setLocalStorage(key, value) {localStorage[key] = value;
}

您可以在Microsoft的文档中阅读有关其工作原理的更多信息。

4. 将按钮链接到开关

启用主题切换分为三个部分:

  1. 用户选择——在这种情况下,一个切换按钮。您还可以使用下拉列表或更定制的选择。
  2. MainLayout.razor文件中切换主题。
  3. 将选择链接到切换。我们将使用为此调用ThemeService的服务。

Dot Net Core使用IOC容器来实现依赖注入,以自动连接类及其依赖项。

该ThemeService类通过ThemeToggle按钮组件或通过操作系统或浏览器更改来处理来自用户的共享主题状态和更改通知。所做的任何更改都会在MainLayout.razor组件中处理。

编码

包含示例项目以演示每种主题切换模式的工作原理。两个示例项目都使用包含的ThemeToggle组件,但是您可以使用自己的组件将其切换出来。

主题库

该库封装了所有核心功能以便于重用:

  • 在主项目中自动包含所有库CSS和JavaScript

1. ThemeToggle组件

  • Aria compliant
  • BEM CSS类命名约定
  • 动画使用最少的动画
  • 亮或暗状态
  • 可选ShowTooltip属性
  • 自定义DarkTipMessage和LightTipMessage属性
  • 支持16、24、43、48像素ButtonSize
  • 自定义Style和classattribute
  • OnDarkModeStateChanged事件
@inject IThemeService themeService<button @attributes="@Attributes"style="@Style"class="@GetComponentCssClass()"aria-label="@GetToolTip()"@onclick="_ => ToggleTheme()"><svg xmlns="http://www.w3.org/2000/svg"max-width="24px" max-height="24px"viewBox="0 0 472.39 472.39"><g class="theme-toggle__sun"><path d="M403.21,167V69.18H305.38L236.2,0,167,69.18H69.18V167L0,236.2l69.18,69.18v97.83H167l69.18,69.18,69.18-69.18h97.83V305.38l69.18-69.18Zm-167,198.17a129,129,0,1,1,129-129A129,129,0,0,1,236.2,365.19Z"/></g><g class="theme-toggle__circle"><circle cx="236.2" cy="236.2" r="103.78"/></g></svg>
</button>

按下按钮时,它会通知ThemeService:

private void ToggleTheme()=> themeService.DarkMode = !themeService.DarkMode;

2. ThemeService(核心)

  • DarkMode主题状态的属性——亮或暗
  • 将状态更改存储到浏览器localstorage中,以记住用户对页面重新加载、更改和以后网站重新访问的选择。
  • 侦听prefers -color-scheme媒体查询更改事件
  • 通知更改的OnDarkModeStateChanged事件

当对状态进行更改时,将执行以下代码:

private async Task SetDarkModeAsync(bool value)
{_darkMode = value;// store user's currently selected color scheme for the appawait (await GetModuleInstance()).SetLocalStorageThemeAsync(_darkMode);OnDarkModeStateChanged?.Invoke(DarkMode);
}

SetLocalStorageThemeAsync是一个扩展方法,它包装了用于存储的JavaScript调用:

internal static class IJSObjectReferenceExtensions
{private static string JSSetLocalStorage = "setLocalStorage"; public static async Task SetLocalStorageAsync(this IJSObjectReference? jsObjRef, string key, string value)=> await jsObjRef!.InvokeVoidAsync(JSSetLocalStorage, key, value).ConfigureAwait(false);public static async Task SetLocalStorageThemeAsync(this IJSObjectReference? jsObjRef, bool IsDarkTheme)=> await jsObjRef!.SetLocalStorageAsync(ThemeKey,IsDarkTheme? DarkThemeValue : LightThemeValue).ConfigureAwait(false);
}

和JavaScript:

function setLocalStorage(key, value) {localStorage[key] = value;
}

3a 主题组件方法

该组件用于样式表切换:

  • 自动选择浅色或深色主题选择
  • 初始化ThemeService并监听OnDarkModeStateChanged事件以进行更改并引发渲染更新。

这是主题切换标记:

@if (ThemeService is not null && ThemeService.DarkMode)
{@if (DarkMode is not null){@DarkMode}
}
else
{@if (LightMode is not null){@LightMode}
}

监听并引发渲染更新的代码:

protected override async Task OnInitializedAsync()
{if (ThemeService is not null){await ThemeService.InitializeAsync()!;ThemeService.OnDarkModeStateChanged+= OnDarkModeChanged;}await base.OnInitializedAsync();
}private void OnDarkModeChanged(bool State) => StateHasChanged();

在您的应用程序中,MainLayout.razor中的组件的使用将是:

<HeadContent><Theming.Themes><DarkMode><link href="css/bootstrap/darkly.min.css" rel="stylesheet" /></DarkMode><LightMode><link href="css/bootstrap/flatly.min.css" rel="stylesheet" /></LightMode></Theming.Themes><link href="css/app.css" rel="stylesheet" /><link href="ThemeTest.styles.css" rel="stylesheet" />
</HeadContent>

3b CSS类更改方法

为CSS类选择手动连接MainLayout.razor:

@inject IThemeService themeService<div class="@GetClassCss()">

以及管理类的代码:

private bool IsDarkMode;protected override async void OnInitialized()
{// uncomment if not using our ThemeToggle component//await themeService.InitializeAsync();themeService.OnDarkModeStateChanged += OnDarkModeChanged;await base.OnInitializedAsync();
}private void OnDarkModeChanged(bool state)
{IsDarkMode = state;StateHasChanged();
}private string GetClassCss()=> "page" + (IsDarkMode ? " dark" : "");

测试主题切换

要测试浅色和深色主题之间的切换,您可以在Windows或Mac OS中设置您的首选项,或使用Web浏览器中的设置/开发人员工具。下面,我列出了在常见浏览器中可以找到这些选项的位置。

Chrome/Edge

1、打开开发者工具

2、单击3个点以获取更多选项,然后单击更多工具,然后选择“渲染”。

3、向下滚动直到到达“prefers-color-scheme”下拉选项。

FireFox

打开开发者工具Page Inspector,有按钮可以在浅色(太阳)和深色(月亮)模式之间切换。

Opera

选择最右侧的“Easy Setup”按钮,您可以在亮、暗和系统操作系统模式之间进行选择。

总结

该库封装了管理主题状态和使用自动存储切换所需的所有功能,支持多种主题技术和现代切换。只需几行代码即可在您自己的项目中实现。

https://www.codeproject.com/Articles/5323228/Blazor-Web-Assembly-WASM-Theme-Switching

Blazor Web Assembly (WASM) 主题切换相关推荐

  1. 基于web assembly (WASM) 的H265 Web播放器

    1 背景 目前这个时间点,原生支持H265(HEVC)播放的浏览器极少,可以说基本没有,主要原因一个是H265的解码有更高的性能要求,从而换取更高的压缩率,目前大多数机器CPU软解H265的超清视频还 ...

  2. 【Web技术】1431- 总结前端主题切换的思考和现代前端样式的解决方案落地

    关于本文 来自:codercao https://juejin.cn/post/7106702604024938503 demo在线体验地址:https://hongqingcao.github.io ...

  3. 【Web技术】1374- 纯 JS 实现灵活的前端主题切换功能

    demo在线体验地址:https://hongqingcao.github.io/v-theme-colors/ 源码地址:https://github.com/HongqingCao/v-theme ...

  4. 英语阅读推荐:主题切换控件 ExpressionBuilder

    这里是Cat in dotNET的Random Clippings系列,专门向大家推荐.NET相关的英文技术文章,每期推荐两篇文章,第一篇适合于英语技术文章阅读的入门者练习阅读能力,而第二篇则适合于进 ...

  5. SpringMVC实现i18n和主题切换

    一.什么是i18n i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是"国际化"的简称.对于程序开发来说,i18n就是能够 ...

  6. Web Assembly背景

    Javascript ,也叫Ecma script,  是这家伙用了 10 天时间赶出来的.. 所以,各位程序猿们,如果你觉得老板 10 天要你们上线一个 App 是一个丧心病狂的事情,那么可以多想想 ...

  7. CI框架主题切换的功能

    CI框架主题切换的功能 本人接触到这个框架不就,属于菜鸟 , 公司现在用CI框架做项目 ,老大要做一个主题切换的功能,说明功能的要求我的脑子里瞬间有几个想法. 脑子里最简单的就是设置全局变量 如 : ...

  8. 主题切换时如何主动去刷新一些资源?

    近来不少同学在修改主题时遇到,切换主题,部分页面不更新的问题,下面来介绍一种切换主题时,主动刷新的方法:1.监听主题切换的广播private static final String DATA_TYPE ...

  9. 在 ASP.NET 2.0 中创建 Web 应用程序主题(一)

    在ASP.net2.0中创建Web应用程序主题 来源:MSDN 适用范围: MicrosoftASP.NET2.0 MicrosoftVisualStudio2005 摘要:StephenWalthe ...

最新文章

  1. 1、lombok的初始使用
  2. vi测试仪维修成功率高吗?_电工电路板检测维修无图电路板的技巧
  3. 你可能不清楚的 Vue Router 深度用法(二)
  4. 性能测试:服务器配置清单分析
  5. 用oracle的ODP.NET创建实体数据模型
  6. JPA /休眠刷新策略初学者指南
  7. Python学习day02_数字类型 与 布尔类型 短路逻辑和运算符优先级
  8. python网络编程-socketserver模块
  9. Logrotate操作手册
  10. 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了
  11. IT小天博客APP版本
  12. AAtitit 项目管理 提升开发效率的项目流程方法模型 哑铃型  橄榄型 直板型titi
  13. 用来这么久的计算机,你是否对计算机中有关数及编码有掌握的呢???那么它来了,让你充分认识计算机有关数和编码的知识~~
  14. Spring实战(使用数据)
  15. 2012年8月版:Oracle数据库技术更新…
  16. 解决笔记本HDMI外接显示器没声音的问题
  17. 编译原理:FIRST集与FOLLOW集
  18. 什么是单工,半双工,全双工
  19. Spring 注解@Value详解
  20. 【专题5: 硬件设计】 之 【15.RC滤波电路】

热门文章

  1. 从1到n年中的闰年个数判断
  2. RPM软件安装包-rpm指令操作
  3. 图神经网络(三):节点分类
  4. 实现屏幕监控的大体思路
  5. ubuntu下添加路径到PATH
  6. el-backtop关于 target is not existed: .page-component__scroll .el-scrollbar__wrap的问题
  7. 云计算发展前景好不好 学了后能胜任哪些岗位
  8. 基于Node.js+Express+MySQL的爱心助农电商管理系统的设计与实现(附源码)
  9. uip-学习笔记(移植篇)
  10. C# SolidWorks 二次开发 API ---读取零件相关属性