基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)

系列文章

  1. 使用 abp cli 搭建项目

  2. 给项目瘦身,让它跑起来

  3. 完善与美化,Swagger登场

  4. 数据访问和代码优先

  5. 自定义仓储之增删改查

  6. 统一规范API,包装返回模型

  7. 再说Swagger,分组、描述、小绿锁

  8. 接入GitHub,用JWT保护你的API

  9. 异常处理和日志记录

  10. 使用Redis缓存数据

  11. 集成Hangfire实现定时任务处理

  12. 用AutoMapper搞定对象映射

  13. 定时任务最佳实战(一)

  14. 定时任务最佳实战(二)

  15. 定时任务最佳实战(三)

  16. 博客接口实战篇(一)

  17. 博客接口实战篇(二)

  18. 博客接口实战篇(三)

  19. 博客接口实战篇(四)

  20. 博客接口实战篇(五)

  21. Blazor实战系列(一)

  22. Blazor实战系列(二)

  23. Blazor实战系列(三)

  24. Blazor实战系列(四)

  25. Blazor实战系列(五)

  26. Blazor实战系列(六)

  27. Blazor实战系列(七)

  28. Blazor实战系列(八)


终于要接近尾声了,上一篇基本上将文章模块的所有功能都完成了,整个博客页面也都完成了,本篇主要来美化几个地方,修修补补。

编辑器主题切换

当我们新增和编辑文章的时候,默认编辑器是白色的,如果点击了头部切换主题按钮,我想要把编辑器主题颜色也做相应的改变该如何去实现呢?

刚好,editor.md是支持主题切换的,这就比较舒服了,直接按照要求调用对应的方法即可。

app.jsrenderEditor函数中我们已经自定义了三个参数themeeditorThemepreviewTheme,这三个参数就是来改变编辑器主题颜色的。

还是将值存在localStorage中,和我们博客的主题切换一样,这里叫editorTheme

theme: localStorage.editorTheme || 'default',
editorTheme: localStorage.editorTheme === 'dark' ? 'pastel-on-dark' : 'default',
previewTheme: localStorage.editorTheme || 'default',

默认从localStorage中取数据,如果没取到的话,给对应的默认值。第二个参数有点特殊,用了一个三元表达式给不同的值。

然后在主题切换的时候也对编辑器做相应的调整即可。

打开Header.razor头部组件,找到SwitchTheme()切换主题的方法,添加一句await Common.SwitchEditorTheme(currentTheme);

/// <summary>
/// 切换主题
/// </summary>
private async Task SwitchTheme()
{currentTheme = currentTheme == "Light" ? "Dark" : "Light";await Common.SetStorageAsync("theme", currentTheme);await Common.InvokeAsync("window.func.switchTheme");var uri = await Common.CurrentUri();if (uri.AbsolutePath.StartsWith("/admin/post")){await Common.SwitchEditorTheme(currentTheme);}
}

将具体切换逻辑放到SwitchEditorTheme中,他接收一个参数currentTheme,用来判断是切换黑的还是白的。

/// <summary>
/// 切换编辑器主题
/// </summary>
/// <param name="currentTheme"></param>
/// <returns></returns>
public async Task SwitchEditorTheme(string currentTheme)
{var editorTheme = currentTheme == "Light" ? "default" : "dark";await SetStorageAsync("editorTheme", editorTheme);await InvokeAsync("window.func.switchEditorTheme");
}

切换主题之前拿到当前URI对象,判断当前请求的链接是否是新增和更新文章的那个页面,即"/admin/post",才去执行切换编辑器主题的方法,当不是这个页面的时候,编辑器是没有渲染出来的,如果也执行这段代码就会报错。

去看看效果。

文章详情页美化

现在的文章详情页是没有将markdown格式渲染出来的,这里还是使用editor.md提供的方法,因为需要加载几个js文件,然后才能渲染样式。

所以还是在app.js添加一段代码。

renderMarkdown: async function () {await this._loadScript('./editor.md/lib/zepto.min.js').then(function () {func._loadScript('./editor.md/lib/marked.min.js').then(function () {func._loadScript('./editor.md/lib/prettify.min.js').then(function () {func._loadScript('./editor.md/editormd.js').then(function () {editormd.markdownToHTML("content");});});});});
},

然后在文章详情页的组件Post.razor中修改代码,当数据加载完成后调用renderMarkdown即可,然后还需要引用一个css文件editormd.preview.css

提供一下Post.razor最终的代码。

@page "/post/{year:int}/{month:int}/{day:int}/{name}"<link href="./editor.md/css/editormd.preview.css" rel="stylesheet" />@if (post == null)
{<Loading />
}
else
{@if (post.Success){var _post = post.Result;<article class="post-wrap"><header class="post-header"><h1 class="post-title">@_post.Title</h1><div class="post-meta">Author: <a itemprop="author" rel="author" href="javascript:;">@_post.Author</a><span class="post-time">Date: <a href="javascript:;">@_post.CreationTime</a></span><span class="post-category">Category:<a href="/category/@_post.Category.DisplayName/">@_post.Category.CategoryName</a></span></div></header><div class="post-content" id="content">@((MarkupString)_post.Html)</div><p class="post-copyright"><p class="copyright-item"><span>Author:</span><span>@_post.Author</span></p><p class="copyright-item"><span>Permalink:</span><span><a href="/post@_post.Url">https://meowv.com/post@_post.Url</a></span></p><p class="copyright-item"><span>License:</span><span>本文采用<a target="_blank" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"> 知识共享 署名-非商业性使用-禁止演绎(CC BY-NC-ND)国际许可协议 </a>进行许可</span></p></p><p class="post-tags"><div><span>Tag(s):</span><span class="tag">@if (_post.Tags.Any()){@foreach (var tag in _post.Tags){<a href="/tag/@tag.DisplayName/"># @tag.TagName</a>}}</span></div><div><a @onclick="@(async () => await Common.NavigateTo("/posts"))">back</a><span>· </span><a href="/">home</a></div></p><p class="post-nav">@if (_post.Previous != null){<a class="prev"rel="prev"@onclick="@(async () => await FetchData(_post.Previous.Url))"href="/post@_post.Previous.Url">@_post.Previous.Title</a>}@if (_post.Next != null){<a class="next"rel="next"@onclick="@(async () => await FetchData(_post.Next.Url))"href="/post@_post.Next.Url">@_post.Next.Title</a>}</p></article>}else{<ErrorTip />}
}@code {[Parameter]public int year { get; set; }[Parameter]public int month { get; set; }[Parameter]public int day { get; set; }[Parameter]public string name { get; set; }/// <summary>/// URL/// </summary>private string url => $"/{year}/{(month >= 10 ? month.ToString() : $"0{month}")}/{(day >= 10 ? day.ToString() : $"0{day}")}/{name}/";/// <summary>/// 文章详情数据/// </summary>private ServiceResult<PostDetailDto> post;/// <summary>/// 初始化/// </summary>protected override async Task OnInitializedAsync(){await FetchData(url);}/// <summary>/// 请求数据,渲染页面/// </summary>/// <param name="url"></param>/// <returns></returns>private async Task FetchData(string url, bool isPostNav = false){post = await Http.GetFromJsonAsync<ServiceResult<PostDetailDto>>($"/blog/post?url={url}");await Common.InvokeAsync("window.func.renderMarkdown");}
}

到这里整个开发工作便结束了,这里只是一个小小的实战系列记录,没有深层次的剖析研究Blazor的所有使用方式。

如果本系列对你有些许帮助,便是我最大的收获,欢迎大家关注我的公众号:阿星Plus。

开源地址:https://github.com/Meowv/Blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SilkierQuartz 1.0.21 发布, 是一个 Quartz.NET 的强大且简单的Web管理工具和承载组件...

SilkierQuartz 是一个新的合并了 Quartzmin 和 QuartzHostedService的组件!Quartz.NET 是一个完整的开源的任务规划系统&#xff0c;从小应用至大型企业级应用都可以适用.Quartzmin Quartzmin 是一个 Quartz.NET 的强大且简单的Web管理工具QuartzHostedService QuartzHostedSer…

用C#在STM32上写第一个Hello world

随着微软放弃.Net MF ,通过C#编写STM32 平台上的程序变得渺茫&#xff0c; 但是&#xff0c; 别着急&#xff0c; 目前至少有两个社区在做这件事情&#xff0c; 传承了微软的.Net MF , 一家是 nanoframework,另外一家比较封闭的是 GHI Electronics 地址是: https://github.com/…

如何找到Eclipse左侧项目栏

如何找到Eclipse左侧项目栏 window --> Show View --> other --> Java–> package Explorer

深入async/await知多少

.net的async/await功能相信对很多人来说并不陌生了&#xff0c;有人感觉这功能很好&#xff0c;但也有人说这功能不好容易产生一些莫名其妙的死锁&#xff1b;有人说这些异步功能也有人说这是同步功能。其实在使用async/await的有多少人真的了解它们呢&#xff1f;接下来详细地…

微软正式发布 gRPC-Web for .NET

今年一月份的时候&#xff0c;微软曾宣布对 gRPC-Web for .NET 的实验性支持微软实验性地对 .NET 支持 gRPC-Web&#xff0c;现在它已正式发布。gRPC 是谷歌开源的高性能、通用 RPC 框架&#xff0c;支持包括 .NET 在内的多种编程语言。它面向移动和基于 HTTP/2 标准设计&#…

Java多线程(review)

文章目录线程状态线程方法线程停止线程休眠——sleep网络延时模拟倒计时与打印当前系统时间线程礼让——yield线程强制执行——Join线程状态线程优先级守护线程不安全案例死锁Lock锁线程状态 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后&#xff0c;该线…

利用Azure Functions和k8s构建Serverless计算平台

题记&#xff1a;昨晚在一个技术社区直播分享了“利用Azure Functions和k8s构建Serverless计算平台”这一话题。整个分享分为4个部分&#xff1a;Serverless概念的介绍、Azure Functions的简单介绍、k8s和KEDA的介绍和最后的演示。ServerlessServerless其实包含了两种概念&…

基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目

系列文章使用 abp cli 搭建项目给项目瘦身&#xff0c;让它跑起来完善与美化&#xff0c;Swagger登场数据访问和代码优先自定义仓储之增删改查统一规范API&#xff0c;包装返回模型再说Swagger&#xff0c;分组、描述、小绿锁接入GitHub&#xff0c;用JWT保护你的API异常处理和…

对 JsonConvert 的认识太肤浅了,终于还是遇到了问题

一&#xff1a;背景1. 讲故事在开始本文之前&#xff0c;真的好想做个问卷调查&#xff0c;到底有多少人和我一样&#xff0c;对 JsonConvert 的认识只局限在 SerializeObject 和 DeserializeObject 这两个方法上(┬&#xff3f;┬), 这样我也好结伴同行&#xff0c;不再孤单落…

.Net微服务实战之DevOps篇

技术只是基础该系列的两篇文章《.Net微服务实战之技术选型篇》和《.Net微服务实战之技术架构分层篇》都是以技术角度出发描述微服务架构的实施。如果技术选型篇叙述的是工具&#xff0c;那么架构分层篇讲的就是技巧&#xff0c;而本篇要讨论的就是原则。一直以来我会给身边向我…

阿里云挑战赛

文章目录第一题题目&#xff1a;题解&#xff1a;第二题题目题解第三题题目题解第四题题目&#xff1a;题解第五题题目题解第六题题目题解第七题题目&#xff1a;题解第八题题目&#xff1a;题解;题解赛后出第一题 题目&#xff1a; 【单选】filter 方法意图过滤传入的订单列…

使用C#编写STM32对接物联网平台IoTSharp发送遥测数据

在之前的文章中&#xff0c; 我们阐述了如何用C#在STM32上写第一个Hello world &#xff0c; 有朋友抱怨国内介绍文章&#xff0c; 都是一个 Hello world &#xff0c; 然后再也没有音讯&#xff0c; 写到这里我想提一下我的初心&#xff0c; 那就是告诉所有人C#无所不能&…

JavaMVC之JSON

JSON 8.1、什么是JSON&#xff1f; JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式&#xff0c;目前使用特别广泛。采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写…

龙芯团队完成CoreCLR MIPS64移植,在github开源

国产龙芯的软件生态之中.NET不会缺席&#xff0c;毕竟 C# 与 .NetCore/Mono 也是全球几大主流的编程语言和运行平台之一&#xff0c;最近一段时间听到太多的鼓吹政务领域不支持.NET&#xff0c; 大家都明白这是某些人为了自己的利益打压使用.NET技术的公司&#xff0c;我今天写…

来谈一谈专注力的真相

这是头哥侃码的第205篇原创在日常生活&#xff08;或工作&#xff09;中&#xff0c;你有没有遇上过这样的情况&#xff1f;比如你正在跟小伙伴讨论一个技术方案&#xff0c;聊着聊着&#xff0c;突然小A脑袋一抽筋&#xff0c;问你&#xff1a;“老大&#xff0c;咱们这周五晚…

Java访问控制修饰符

访问控制修饰符 Java中&#xff0c;可以使用访问控制符来保护对类、变量、方法和构造方法的访问。 Java 支持 4 种不同的访问权限。 default (即默认&#xff0c;什么也不写&#xff09;: 在同一包内可见&#xff0c;不使用任何修饰符。 使用对象&#xff1a;类、接口、变量…

数据结构与算法专题——第三题 最长公共子序列

一&#xff1a;作用最长公共子序列的问题常用于解决字符串的相似度&#xff0c;是一个非常实用的算法&#xff0c;作为码农&#xff0c;此算法是我们的必备基本功。二&#xff1a;概念举个例子&#xff0c;cnblogs这个字符串中子序列有多少个呢&#xff1f;很显然有27个&#x…

Java实现两个递增有序链表合并成一个递增有序链表和两个非递减有序链表合成一个非递增有序链表

代码如下: package sjjgniub;import java.util.LinkedList; import java.util.Scanner;SuppressWarnings("all") public class LinkList {private class Node{int data;Node next;public Node(){}public Node(int data){this.data data;next null;}}Node head nu…

职场PUA到底有多可怕?

阅读本文大概需要 5.2分钟。“小张&#xff0c;好好干啊&#xff0c;明年一定给你加薪&#xff01;” 。从小张入职这家公司起&#xff0c;这是老板对小张第三次这么说了。小张每天干到晚上12点&#xff0c;任劳任怨&#xff0c;虽然一直没涨过工资&#xff0c;但是老板的不断认…