系列文章

  1. 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目
  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来
  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场
  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先
  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 自定义仓储之增删改查
  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 统一规范API,包装返回模型
  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 再说Swagger,分组、描述、小绿锁
  8. 基于 abp vNext 和 .NET Core 开发博客项目 - 接入GitHub,用JWT保护你的API
  9. 基于 abp vNext 和 .NET Core 开发博客项目 - 异常处理和日志记录
  10. 基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据
  11. 基于 abp vNext 和 .NET Core 开发博客项目 - 集成Hangfire实现定时任务处理
  12. 基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射
  13. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)
  14. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)
  15. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)
  16. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)
  17. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)
  18. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)
  19. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四)
  20. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)
  21. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(一)
  22. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二)
  23. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(三)
  24. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(四)
  25. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五)
  26. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六)
  27. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(七)
  28. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(八)

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

编辑器主题切换

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

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

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

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

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

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

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

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

  1. /// <summary>
  2. /// 切换主题
  3. /// </summary>
  4. private async Task SwitchTheme()
  5. {
  6. currentTheme = currentTheme == "Light" ? "Dark" : "Light";
  7. await Common.SetStorageAsync("theme", currentTheme);
  8. await Common.InvokeAsync("window.func.switchTheme");
  9. var uri = await Common.CurrentUri();
  10. if (uri.AbsolutePath.StartsWith("/admin/post"))
  11. {
  12. await Common.SwitchEditorTheme(currentTheme);
  13. }
  14. }

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

  1. /// <summary>
  2. /// 切换编辑器主题
  3. /// </summary>
  4. /// <param name="currentTheme"></param>
  5. /// <returns></returns>
  6. public async Task SwitchEditorTheme(string currentTheme)
  7. {
  8. var editorTheme = currentTheme == "Light" ? "default" : "dark";
  9. await SetStorageAsync("editorTheme", editorTheme);
  10. await InvokeAsync("window.func.switchEditorTheme");
  11. }

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

去看看效果。

文章详情页美化

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

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

  1. renderMarkdown: async function () {
  2. await this._loadScript('./editor.md/lib/zepto.min.js').then(function () {
  3. func._loadScript('./editor.md/lib/marked.min.js').then(function () {
  4. func._loadScript('./editor.md/lib/prettify.min.js').then(function () {
  5. func._loadScript('./editor.md/editormd.js').then(function () {
  6. editormd.markdownToHTML("content");
  7. });
  8. });
  9. });
  10. });
  11. },

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

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

  1. @page "/post/{year:int}/{month:int}/{day:int}/{name}"
  2. <link href="./editor.md/css/editormd.preview.css" rel="stylesheet" />
  3. @if (post == null)
  4. {
  5. <Loading />
  6. }
  7. else
  8. {
  9. @if (post.Success)
  10. {
  11. var _post = post.Result;
  12. <article class="post-wrap">
  13. <header class="post-header">
  14. <h1 class="post-title">@_post.Title</h1>
  15. <div class="post-meta">
  16. Author: <a itemprop="author" rel="author" href="javascript:;">@_post.Author</a>
  17. <span class="post-time">
  18. Date: <a href="javascript:;">@_post.CreationTime</a>
  19. </span>
  20. <span class="post-category">
  21. Category:<a href="/category/@_post.Category.DisplayName/">@_post.Category.CategoryName</a>
  22. </span>
  23. </div>
  24. </header>
  25. <div class="post-content" id="content">
  26. @((MarkupString)_post.Html)
  27. </div>
  28. <section class="post-copyright">
  29. <p class="copyright-item">
  30. <span>Author:</span>
  31. <span>@_post.Author</span>
  32. </p>
  33. <p class="copyright-item">
  34. <span>Permalink:</span>
  35. <span><a href="/post@_post.Url">https://meowv.com/post@_post.Url</a></span>
  36. </p>
  37. <p class="copyright-item">
  38. <span>License:</span>
  39. <span>本文采用<a target="_blank" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"> 知识共享 署名-非商业性使用-禁止演绎(CC BY-NC-ND)国际许可协议 </a>进行许可</span>
  40. </p>
  41. </section>
  42. <section class="post-tags">
  43. <div>
  44. <span>Tag(s):</span>
  45. <span class="tag">
  46. @if (_post.Tags.Any())
  47. {
  48. @foreach (var tag in _post.Tags)
  49. {
  50. <a href="/tag/@tag.DisplayName/"># @tag.TagName</a>
  51. }
  52. }
  53. </span>
  54. </div>
  55. <div>
  56. <a @onclick="@(async () => await Common.NavigateTo("/posts"))">back</a>
  57. <span>· </span>
  58. <a href="/">home</a>
  59. </div>
  60. </section>
  61. <section class="post-nav">
  62. @if (_post.Previous != null)
  63. {
  64. <a class="prev"
  65. rel="prev"
  66. @onclick="@(async () => await FetchData(_post.Previous.Url))"
  67. href="/post@_post.Previous.Url">@_post.Previous.Title</a>
  68. }
  69. @if (_post.Next != null)
  70. {
  71. <a class="next"
  72. rel="next"
  73. @onclick="@(async () => await FetchData(_post.Next.Url))"
  74. href="/post@_post.Next.Url">
  75. @_post.Next.Title
  76. </a>
  77. }
  78. </section>
  79. </article>
  80. }
  81. else
  82. {
  83. <ErrorTip />
  84. }
  85. }
  86. @code {
  87. [Parameter]
  88. public int year { get; set; }
  89. [Parameter]
  90. public int month { get; set; }
  91. [Parameter]
  92. public int day { get; set; }
  93. [Parameter]
  94. public string name { get; set; }
  95. /// <summary>
  96. /// URL
  97. /// </summary>
  98. private string url => $"/{year}/{(month >= 10 ? month.ToString() : $"0{month}")}/{(day >= 10 ? day.ToString() : $"0{day}")}/{name}/";
  99. /// <summary>
  100. /// 文章详情数据
  101. /// </summary>
  102. private ServiceResult<PostDetailDto> post;
  103. /// <summary>
  104. /// 初始化
  105. /// </summary>
  106. protected override async Task OnInitializedAsync()
  107. {
  108. await FetchData(url);
  109. }
  110. /// <summary>
  111. /// 请求数据,渲染页面
  112. /// </summary>
  113. /// <param name="url"></param>
  114. /// <returns></returns>
  115. private async Task FetchData(string url, bool isPostNav = false)
  116. {
  117. post = await Http.GetFromJsonAsync<ServiceResult<PostDetailDto>>($"/blog/post?url={url}");
  118. await Common.InvokeAsync("window.func.renderMarkdown");
  119. }
  120. }

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

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

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

基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)的更多相关文章

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

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

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

随机推荐

  1. 《机器学习_08_代价敏感学习_添加sample_weight支持》

    简介 这一节主要是为模型打补丁,在这之前笔者已经介绍并实现了几种典型的机器学习模型,比如线性回归.logistic回归.最大熵.感知机.svm等,但目前它们都有一个共性,那就是构造的损失函数对每个样本 ...

  2. SQL——SQL别名、UNION和SELECT INTO

    Alias(别名) - 为列名称和表名称指定别名    语法:表SELECT columnName(s) FROM tableName AS aliasName          列SELECT co ...

  3. SVN创建分支的相关操作

    目的是为了在项目中进行相应的功能操作的时候避免项目的报错还能进行还原 1.在相应的位置创建分支 项目过大的只在 功能的位置 进行创建分支 Angular的src 不要在其下面进行创建分支 他有严格的文 ...

  4. idea的生成类注释和方法注释

    sttings中选择 类注释 /** * @program: ${PROJECT_NAME} * * @description: ${description} * * @author: xiaozha ...

  5. Map,HashMap五种遍历方法

    假设有数组            HashMap<Integer, String> h=new HashMap<Integer,String>();        h.put( ...

  6. DQN(Deep Q-learning)入门教程(三)之蒙特卡罗法算法与Q-learning算法

    蒙特卡罗法 在介绍Q-learing算法之前,我们还是对蒙特卡罗法(MC)进行一些介绍.MC方法是一种无模型(model-free)的强化学习方法,目标是得到最优的行为价值函数\(q_*\).在前面一 ...

  7. S32DS编译程序出现Type region `SRAM' overflowed by 19240 bytes错误

    用S32DS编译工程遇到Type region `SRAM' overflowed by 19240 bytes错误(芯片为S9KEAZ64AMLH) 程序中未初始化的变量存放SRAM中 当程序出现未 ...

  8. Rocket - tilelink - Monitor

    https://mp.weixin.qq.com/s/6e-G5RSQc7Xje7mQj8-Lag   简单介绍Monitor的实现.   ​​   1. 基本介绍   用于监控各个channel上的 ...

  9. Rocket - tilelink - mask

    https://mp.weixin.qq.com/s/Gqv09RIgSSg5VKe-wb4aGg   讨论tilelink中使用MaskGen生成mask的用法.   1. tilelink中的ma ...

  10. jchdl - RTL Value Propagation

    https://mp.weixin.qq.com/s/2_0yQYdHlSQzPw7vX7NuHA     ​​ 因为建模方式的不同,RTL值的传播不同于GSL值的传播.   jchdl GSL模型的 ...