系列文章

基于 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 实战系列(二)

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

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

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

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

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

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

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

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

上一篇完成了博客的分页查询文章列表页面的数据绑定和分页功能,本篇将继续完成剩下的几个页面。

在开始主题之前重新解决上一篇的最后一个问题,当点击了头部组件的/posts链接时直接强制刷新了页面,经过查看文档和实践有了更好的解决方案。

先将头部组件Header.razor中的NavLink恢复成Posts,不需要点击事件了。

然后在Posts.razor中添加生命周期函数OnParametersSetAsync(),在初始化完成后执行。

///

/// 初始化完成后执行

///

///

protected override async Task OnParametersSetAsync()

{

if (!page.HasValue)

{

page = 1;

await RenderPage(page);

}

}

判断当前page参数是否有值,有值的话说明请求肯定是来自于翻页,当page没有值的时候就说明是头部的菜单点进来的。那么此时给page赋值为1,调用API加载数据即可。

分类列表

Categories.razor是分类列表页面,上篇文章已经实现了从API获取数据的方法,所以这里就很简单了,指定接受类型,然后在生命周期初始化OnInitializedAsync()中去获取数据。

@code{

///

/// categories

///

private ServiceResult> categories;

///

/// 初始化

///

protected override async Task OnInitializedAsync()

{

// 获取数据

categories = await Http.GetFromJsonAsync>>($"/blog/categories");

}

}

当获取到数据的时候进行绑定,没有数据的时候还是显示加载中的组件让他转圈圈。

@if (categories == null)

{

}

else

{

- Categories -

@if (categories.Success && categories.Result.Any())

{

@foreach (var item in categories.Result)

{

}

}

else

{

}

}

直接循环返回的数据列表categories.Result,绑定数据就好,当获取失败或者没有返回数据的时候显示错误提示组件

标签列表

Categories.razor是标签列表页面,和分类列表HTML结构差不多一样的,除了返回类型和接口地址不一样,将上面代码复制过来改改即可。

@code{

///

/// tags

///

private ServiceResult> tags;

///

/// 初始化

///

protected override async Task OnInitializedAsync()

{

// 获取数据

tags = await Http.GetFromJsonAsync>>($"/blog/tags");

}

}

@if (tags == null)

{

}

else

{

- Tags -

@if (tags.Success && tags.Result.Any())

{

@foreach (var item in tags.Result)

{

@item.TagName(@item.Count)

}

}

else

{

}

}

友链列表

FriendLinks.razor是友情链接列表页面,实现方式和上面两个套路一模一样。

@code {

///

/// friendlinks

///

private ServiceResult> friendlinks;

///

/// 初始化

///

protected override async Task OnInitializedAsync()

{

// 获取数据

friendlinks = await Http.GetFromJsonAsync>>($"/blog/friendlinks");

}

}

@if (friendlinks == null)

{

}

else

{

- FriendLinks -

@if (friendlinks.Success && friendlinks.Result.Any())

{

@foreach (var item in friendlinks.Result)

{

}

}

else

{

}

}

文章列表(分类)

Posts.Category.razor是根据分类查询文章列表页面,他接受一个参数name,我们要根据name去API查询数据然后绑定页面即可。

这里的参数name实际上就是从标签列表传递过来的DisplayName的值,它是一个比较友好的名称,我们还要通过这个值去查询真正的分类名称进行展示,所以这里需要调用两个API,这点在设计API的时候没有考虑好,我们其实可以将这两个API合并变成一个,后续再进行优化吧,这里就请求两次。

添加两个接收参数:分类名称和返回的文章列表数据。

///

/// 分类名称

///

private string categoryName;

///

/// 文章列表数据

///

private ServiceResult> posts;

然后在OnInitializedAsync()初始化方法中调用API获取数据,赋值给变量。

///

/// 初始化

///

protected override async Task OnInitializedAsync()

{

// TODO:获取数据,可以在API中合并这两个请求。

var category = await Http.GetFromJsonAsync>($"/blog/category?name={name}");

posts = await Http.GetFromJsonAsync>>($"/blog/posts/category?name={name}");

if (category.Success)

{

categoryName = category.Result;

}

}

有了数据,直接在页面上进行循环绑定。

@if (posts == null)

{

}

else

{

@if (categoryName != null)

{

- Category · @categoryName -

}

@if (posts.Success && posts.Result.Any())

{

@foreach (var item in posts.Result)

{

@item.Year

@foreach (var post in item.Posts)

{

@post.Title

@post.CreationTime

}

}

}

else

{

}

}

文章列表(标签)

Posts.Tag.razor是根据标签查询文章列表,这个和分类查询文章列表实现方式一样,直接上代码。

@code {

///

/// 标签名称参数

///

[Parameter]

public string name { get; set; }

///

/// 标签名称

///

private string tagName;

///

/// 文章列表数据

///

private ServiceResult> posts;

///

/// 初始化

///

protected override async Task OnInitializedAsync()

{

// TODO:获取数据,可以在API中合并这两个请求。

var tag = await Http.GetFromJsonAsync>($"/blog/tag?name={name}");

posts = await Http.GetFromJsonAsync>>($"/blog/posts/tag?name={name}");

if (tag.Success)

{

tagName = tag.Result;

}

}

}

@if (posts == null)

{

}

else

{

@if (tagName != null)

{

- Tag · @tagName -

}

@if (posts.Success && posts.Result.Any())

{

@foreach (var item in posts.Result)

{

@item.Year

@foreach (var post in item.Posts)

{

@post.Title

@post.CreationTime

}

}

}

else

{

}

}

以上完成了以上几个页面的数据绑定,页面之间的跳转已经关联起来了,然后还剩下文章详情页,大家可以先自己动手完成它,今天就到这里,未完待续...

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

查看原文