1. 程式人生 > >基於 abp vNext 和 .NET Core 開發部落格專案 - Blazor 實戰系列(三)

基於 abp vNext 和 .NET Core 開發部落格專案 - Blazor 實戰系列(三)

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 給專案瘦身,讓它跑起來](https://www.cnblogs.com/meowv/p/12896898.html)** 3. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 完善與美化,Swagger登場](https://www.cnblogs.com/meowv/p/12909558.html)** 4. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 資料訪問和程式碼優先](https://www.cnblogs.com/meowv/p/12913676.html)** 5. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 自定義倉儲之增刪改查](https://www.cnblogs.com/meowv/p/12916613.html)** 6. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 統一規範API,包裝返回模型](https://www.cnblogs.com/meowv/p/12924409.html)** 7. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 再說Swagger,分組、描述、小綠鎖](https://www.cnblogs.com/meowv/p/12924859.html)** 8. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 接入GitHub,用JWT保護你的API](https://www.cnblogs.com/meowv/p/12935693.html)** 9. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 異常處理和日誌記錄](https://www.cnblogs.com/meowv/p/12943699.html)** 10. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用Redis快取資料](https://www.cnblogs.com/meowv/p/12956696.html)** 11. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 整合Hangfire實現定時任務處理](https://www.cnblogs.com/meowv/p/12961014.html)** 12. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 用AutoMapper搞定物件對映](https://www.cnblogs.com/meowv/p/12966092.html)** 13. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(一)](https://www.cnblogs.com/meowv/p/12971041.html)** 14. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(二)](https://www.cnblogs.com/meowv/p/12974439.html)** 15. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(三)](https://www.cnblogs.com/meowv/p/12980301.html)** 16. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(一)](https://www.cnblogs.com/meowv/p/12987623.html)** 17. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(二)](https://www.cnblogs.com/meowv/p/12994914.html)** 18. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(三)](https://www.cnblogs.com/meowv/p/13039883.html)** 19. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(四)](https://www.cnblogs.com/meowv/p/13043084.html)** 20. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(五)](https://www.cnblogs.com/meowv/p/13046603.html)** 21. **[基於 abp vNext 和 .NET Core 開發部落格專案 - Blazor 實戰系列(一)](https://www.cnblogs.com/meowv/p/13061975.html)** 22. **[基於 abp vNext 和 .NET Core 開發部落格專案 - Blazor 實戰系列(二)](https://www.cnblogs.com/meowv/p/13065295.html)** --- 上一篇完成了部落格的主題切換,選單和二維碼的顯示與隱藏功能,本篇繼續完成分頁查詢文章列表的資料展示。 ## 新增頁面 現在點選頁面上的連結,都會提示錯誤訊息,因為沒有找到對應的路由地址。先在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`。 ```html ``` ```csharp //Posts.razor @page "/posts/" @page "/posts/page/{page:int}" @page "/posts/{page:int}" @code { /// /// 當前頁碼 /// [Parameter] public int? page { get; set; } } ``` 這裡我加了三條,可以匹配沒有page引數,帶page引數的,`/posts/page/{page:int}`這個大家可以不用加,我是用來相容目前線上的部落格路由的。總的來說可以匹配到:`/posts`、`/posts/1`、`/posts/page/1`這樣的路由。 ```csharp //Posts.Category.razor @page "/category/{name}"
@code { /// /// 分類名稱引數 /// [Parameter] public string name { get; set; } } ``` 根據分類名稱查詢文章列表頁面,name當作分類名稱引數,可以匹配到類似於:`/category/aaa`、`/category/bbb`這樣的路由。 ```csharp //Posts.Tag.razor @page "/tag/{name}" @code { /// /// 標籤名稱引數 /// [Parameter] public string name { get; set; } } ``` 這個根據標籤名稱查詢文章列表頁面和上面差不多一樣,可以匹配到:`/tag/aaa`、`/tag/bbb`這樣的路由。 ```csharp //Post.razor @page "/post/{year:int}/{month:int}/{day:int}/{name}"
@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`這樣的。 ```csharp //Categories.razor @page "/categories"
//Tags.razor @page "/tags" //FriendLinks.razor @page "/friendlinks" ``` 分類、標籤、友情連結都是固定的路由,像上面這樣就不多說了,然後還剩一個`Apps.razor`。 ```html //Apps.razor @page "/apps"

- Apps -

  • 吐個槽_留言板

  • 友情連結

``` 在裡面添加了一個友情連結的入口,和一個 [騰訊兔小巢](https://support.qq.com/products/75616) 的連結,歡迎大家吐槽留言噢。 ![1](https://img2020.cnblogs.com/blog/891843/202006/891843-20200609214326543-1196371440.png) 現在可以執行一下看看,點選所有的連結都不會提示錯誤,只要路由匹配正確就會出現載入中的圈圈了。 ## 文章列表 在做文章列表的資料繫結的時候遇到了大坑,有前端開發經驗的都知道,JavaScript弱型別語言中接收json資料隨便玩,但是在Blazor中我試了下動態接受傳遞過來的JSON資料,一直報錯壓根執行不起來。所以在請求api接收資料的時候需要指定接收物件,那就好辦了我就直接引用API中的`.Application.Contracts`就行了啊,但是緊接著坑又來了,目標框架對不上,引用之後也執行不起來,這裡應該是之前沒有設計好。 於是,我就想了一個折中的辦法吧,將API中的返回物件可以用到的DTO先手動拷貝一份到Blazor專案中,後續可以考慮將公共的返回模型做成Nuget包,方便使用。 那麼,最終就是在Blazor中新增一個Response資料夾,用來放接收物件,裡面的內容看圖: ![2](https://img2020.cnblogs.com/blog/891843/202006/891843-20200609215727896-297305034.png) 有點傻,先這樣解決,後面在做進一步的優化吧。 將我們複製進來的東東,在`_Imports.razor`中新增引用。 ```csharp //_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的返回資料的接收型別引數。 ```csharp /// /// 限制條數 /// private int Limit = 15; /// /// 總頁碼 /// private int TotalPage; /// /// 文章列表資料 /// private ServiceResult> posts; ``` 然後當頁面初始化的時候,去載入資料,渲染頁面,因為page引數可能存在為空的情況,所以要考慮進去,當為空的時候給他一個預設值1。 ```csharp /// /// 初始化 /// protected override async Task OnInitializedAsync() { // 設定預設值 page = page.HasValue ? page : 1; await RenderPage(page); } /// /// 點選頁碼重新渲染資料 /// /// /// private async Task RenderPage(int? page) { // 獲取資料 posts = await Http.GetFromJsonAsync>>($"/blog/posts?page={page}&limit={Limit}"); // 計算總頁碼 TotalPage = (int)Math.Ceiling((posts.Result.Total / (double)Limit)); } ``` 在初始化方法中設定預設值,呼叫`RenderPage(...)`獲取到API返回來的資料,並根據返回資料計算出頁碼,這樣就可以繫結資料了。 ```html @if (posts == null) { } else { @if (posts.Success && posts.Result.Item.Any()) { @foreach (var item in posts.Result.Item) {

@item.Year

@foreach (var post in item.Posts) { @post.Title @post.CreationTime } } } else { } } ``` 在載入資料的時候肯定是需要一個等待時間的,因為不可抗拒的原因資料還沒加載出來的時候,可以讓它先轉一會圈圈,當`posts`不為空的時候,再去繫結資料。 在繫結資料,for迴圈頁碼的時候我又遇到了一個坑