系列文章 基於 abp vNext 和 .NET Core 開發博客項目 - 使用 abp cli 搭建項目 基於 abp vNext 和 .NET Core 開發博客項目 - 給項目瘦身,讓它跑起來 基於 abp vNext 和 .NET Core 開發博客項目 - 完善與美化,Swagger登場 ...
系列文章
- 基於 abp vNext 和 .NET Core 開發博客項目 - 使用 abp cli 搭建項目
- 基於 abp vNext 和 .NET Core 開發博客項目 - 給項目瘦身,讓它跑起來
- 基於 abp vNext 和 .NET Core 開發博客項目 - 完善與美化,Swagger登場
- 基於 abp vNext 和 .NET Core 開發博客項目 - 數據訪問和代碼優先
- 基於 abp vNext 和 .NET Core 開發博客項目 - 自定義倉儲之增刪改查
- 基於 abp vNext 和 .NET Core 開發博客項目 - 統一規範API,包裝返回模型
- 基於 abp vNext 和 .NET Core 開發博客項目 - 再說Swagger,分組、描述、小綠鎖
- 基於 abp vNext 和 .NET Core 開發博客項目 - 接入GitHub,用JWT保護你的API
- 基於 abp vNext 和 .NET Core 開發博客項目 - 異常處理和日誌記錄
- 基於 abp vNext 和 .NET Core 開發博客項目 - 使用Redis緩存數據
- 基於 abp vNext 和 .NET Core 開發博客項目 - 集成Hangfire實現定時任務處理
- 基於 abp vNext 和 .NET Core 開發博客項目 - 用AutoMapper搞定對象映射
- 基於 abp vNext 和 .NET Core 開發博客項目 - 定時任務最佳實戰(一)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 定時任務最佳實戰(二)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 定時任務最佳實戰(三)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 博客介面實戰篇(一)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 博客介面實戰篇(二)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 博客介面實戰篇(三)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 博客介面實戰篇(四)
- 基於 abp vNext 和 .NET Core 開發博客項目 - 博客介面實戰篇(五)
- 基於 abp vNext 和 .NET Core 開發博客項目 - Blazor 實戰系列(一)
- 基於 abp vNext 和 .NET Core 開發博客項目 - Blazor 實戰系列(二)
上一篇完成了博客的主題切換,菜單和二維碼的顯示與隱藏功能,本篇繼續完成分頁查詢文章列表的數據展示。
添加頁面
現在點擊頁面上的鏈接,都會提示錯誤消息,因為沒有找到對應的路由地址。先在Pages下創建五個文件夾:Posts、Categories、Tags、Apps、FriendLinks。
然後在對應的文件夾下添加Razor組件。
- Posts文件夾:文章列表頁面
Posts.razor
、根據分類查詢文章列表頁面Posts.Category.razor
、根據標簽查詢文章列表頁面Posts.Tag.razor
、文章詳情頁Post.razor
- Categories文件夾:分類列表頁面
Categories.razor
- Tags文件夾:標簽列表頁面
Tags.razor
- Apps文件夾:
Apps.razor
準備將友情鏈接入口放在裡面 - FriendLinks文件夾:友情鏈接列表頁面
FriendLinks.razor
先分別創建上面這些Razor組件,差不多除了後臺CURD的頁面就這些了,現在來逐個突破。
不管三七二十一,先把所有頁面的路由給確定了,指定頁面路由使用 @page
指令,官方文檔說不支持可選參數,但是可以支持多個路由規則。
預設先什麼都不顯示,可以將之前的載入中圈圈寫成一個組件,供每個頁面使用。
在Shared文件夾添加組件Loading.razor
。
<!--Loading.razor-->
<div class="loader"></div>
//Posts.razor
@page "/posts/"
@page "/posts/page/{page:int}"
@page "/posts/{page:int}"
<Loading />
@code {
/// <summary>
/// 當前頁碼
/// </summary>
[Parameter]
public int? page { get; set; }
}
這裡我加了三條,可以匹配沒有page參數,帶page參數的,/posts/page/{page:int}
這個大家可以不用加,我是用來相容目前線上的博客路由的。總的來說可以匹配到:/posts
、/posts/1
、/posts/page/1
這樣的路由。
//Posts.Category.razor
@page "/category/{name}"
<Loading />
@code {
/// <summary>
/// 分類名稱參數
/// </summary>
[Parameter]
public string name { get; set; }
}
根據分類名稱查詢文章列表頁面,name當作分類名稱參數,可以匹配到類似於:/category/aaa
、/category/bbb
這樣的路由。
//Posts.Tag.razor
@page "/tag/{name}"
<Loading />
@code {
/// <summary>
/// 標簽名稱參數
/// </summary>
[Parameter]
public string name { get; set; }
}
這個根據標簽名稱查詢文章列表頁面和上面差不多一樣,可以匹配到:/tag/aaa
、/tag/bbb
這樣的路由。
//Post.razor
@page "/post/{year:int}/{month:int}/{day:int}/{name}"
<Loading />
@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; }
}
文章詳情頁面的路由有點點複雜,以/post/開頭,加上年月日和當前文章的語義化名稱組成。分別添加了四個參數年月日和名稱,用來接收URL的規則,使用int來設置路由的約束,最終可以匹配到路由:/post/2020/06/09/aaa
、/post/2020/06/9/bbb
這樣的。
//Categories.razor
@page "/categories"
<Loading />
//Tags.razor
@page "/tags"
<Loading />
//FriendLinks.razor
@page "/friendlinks"
<Loading />
分類、標簽、友情鏈接都是固定的路由,像上面這樣就不多說了,然後還剩一個Apps.razor
。
//Apps.razor
@page "/apps"
<div class="container">
<div class="post-wrap">
<h2 class="post-title">- Apps -</h2>
<ul>
<li>
<a target="_blank" href="https://support.qq.com/products/75616"><h3>吐個槽_留言板</h3></a>
</li>
<li>
<NavLink href="/friendlinks"><h3>友情鏈接</h3></NavLink>
</li>
</ul>
</div>
</div>
在裡面添加了一個友情鏈接的入口,和一個 騰訊兔小巢 的鏈接,歡迎大家吐槽留言噢。
現在可以運行一下看看,點擊所有的鏈接都不會提示錯誤,只要路由匹配正確就會出現載入中的圈圈了。
文章列表
在做文章列表的數據綁定的時候遇到了大坑,有前端開發經驗的都知道,JavaScript弱類型語言中接收json數據隨便玩,但是在Blazor中我試了下動態接受傳遞過來的JSON數據,一直報錯壓根運行不起來。所以在請求api接收數據的時候需要指定接收對象,那就好辦了我就直接引用API中的.Application.Contracts
就行了啊,但是緊接著坑又來了,目標框架對不上,引用之後也運行不起來,這裡應該是之前沒有設計好。
於是,我就想了一個折中的辦法吧,將API中的返回對象可以用到的DTO先手動拷貝一份到Blazor項目中,後續可以考慮將公共的返回模型做成Nuget包,方便使用。
那麼,最終就是在Blazor中添加一個Response文件夾,用來放接收對象,裡面的內容看圖:
有點傻,先這樣解決,後面在做進一步的優化吧。
將我們複製進來的東東,在_Imports.razor
中添加引用。
//_Imports.razor
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Meowv.Blog.BlazorApp.Shared
@using Response.Base
@using Response.Blog
@inject HttpClient Http
@inject Commons.Common Common
@inject HttpClient Http
:註入HttpClient
,用它來請求API數據。
現在有了接收對象,接下來就好辦了,來實現分頁查詢文章列表吧。
先添加三個私有變數,限制條數,就是一次載入文章的數量,總頁碼用來計算分頁,還有就是API的返回數據的接收類型參數。
/// <summary>
/// 限制條數
/// </summary>
private int Limit = 15;
/// <summary>
/// 總頁碼
/// </summary>
private int TotalPage;
/// <summary>
/// 文章列表數據
/// </summary>
private ServiceResult<PagedList<QueryPostDto>> posts;
然後當頁面初始化的時候,去載入數據,渲染頁面,因為page參數可能存在為空的情況,所以要考慮進去,當為空的時候給他一個預設值1。
/// <summary>
/// 初始化
/// </summary>
protected override async Task OnInitializedAsync()
{
// 設置預設值
page = page.HasValue ? page : 1;
await RenderPage(page);
}
/// <summary>
/// 點擊頁碼重新渲染數據
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
private async Task RenderPage(int? page)
{
// 獲取數據
posts = await Http.GetFromJsonAsync<ServiceResult<PagedList<QueryPostDto>>>($"/blog/posts?page={page}&limit={Limit}");
// 計算總頁碼
TotalPage = (int)Math.Ceiling((posts.Result.Total / (double)Limit));
}
在初始化方法中設置預設值,調用RenderPage(...)
獲取到API返回來的數據,並根據返回數據計算出頁碼,這樣就可以綁定數據了。
@if (posts == null)
{
<Loading />
}
else
{
<div class="post-wrap archive">
@if (posts.Success && posts.Result.Item.Any())
{
@foreach (var item in posts.Result.Item)
{
<h3>@item.Year</h3>
@foreach (var post in item.Posts)
{
<article class="archive-item">
<NavLink href="@("/post" + post.Url)">@post.Title</NavLink>
<span class="archive-item-date">@post.CreationTime</span>
</article>
}
}
<nav class="pagination">
@for (int i = 1; i <= TotalPage; i++)
{
var _page = i;
if (page == _page)
{
<span class="page-number current">@_page</span>
}
else
{
<a class="page-number" @onclick="@(() => RenderPage(_page))" href="/posts/@_page">@_page</a>
}
}
</nav>
}
else
{
<ErrorTip />
}
</div>
}
在載入數據的時候肯定是需要一個等待時間的,因為不可抗拒的原因數據還沒載入出來的時候,可以讓它先轉一會圈圈,當posts
不為空的時候,再去綁定數據。
在綁定數據,for迴圈頁碼的時候我又遇到了一個坑