基于BootstrapBlazor实现一个用户评论留言板组件效果
网页评论留言板网页评论互动文章评论组件Blazor留言板Blazor评论BootstrapBlazor
Blazor
13
这两天给往网站文章做了个留言板功能,本意是一方面可以给一些网友提供一些帮助,另一方面给网页内容做一些补充,实现了基本的评论嵌套回复功能,还做了后台审核功能。 由于个人网站的备案性质不允许挂评论留言板,所以上线了短暂10分钟后突然意识到不能上就自己默默的下掉了留言互动模块。 但毕竟也是花了不少时间码出来的,所以这里把留言板实现的核心代码部分分享出来(基于blazor实现效果简直不要太简单)
先展示一下效果图 理论上可以多级树状展示
数据库表字段设计部分
| 字段名称| 描述 | | ------ | ------ | | Id | 消息Id | | TargetUrl | 目标网页地址 | | Content | 用户留言内容 | | UserId | 用户Id对应用户系统 | | ParentId | 父级消息Id(默认为1楼) |
C#实体部分 (这部分代码用到Freesql作为数据库orm)
public class GuestBook
{
/// <summary>
/// 消息Id
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 目标网页地址
/// </summary>
public string TargetUrl { get; set; }
/// <summary>
/// 留言内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 发言用户Id
/// </summary>
public Guid UserId { get; set; }
/// <summary>
/// 用户信息(参考Freesql Navigate导航属性)
/// </summary>
[Navigate(nameof(UserId))]
public UserMember GuestUser { get; set; }
/// <summary>
/// 关联父级别消息(即回复目标)
/// </summary>
public Guid ParentId { get; set; } = Guid.Empty;
}
写一个用户评论的UI组件 核心在于实现一个递归UI子组件(这里用了 Bootstrap Blazor UI)
- UI前台混合代码(比较简单)
<li class="mt-3">
<hr />
<div class="row g-2">
<div class="col-auto">
<Avata Size="Size.Medium" Url="@Model.GuestUser.ProfilePicture"></Avatar>
</div>
<div class="col">
<div>
<div class="row">
<div class="col-6">
@{
if (Model.GuestUser.Type == "管理员")
{
<span class="text-info me-2">站长</span>
}
else
{
if (string.IsNullOrWhiteSpace(Model.GuestUser.UserName) || Model.GuestUser.UserName.Length<=5)
{
<span class="text-info me-2">某某网友</span>
}
else{
<span class="text-info me-2">*****@Model.GuestUser.UserName.Substring(5)</span>
}
}
}
</div>
<div class="col-6 text-end">
@{
if (ShowReply)
{
<Anchor Target="anchor1">
<Butto Size="Size.ExtraSmall" OnClick="@(()=>OnSelectedItemsChangedAsync(Model))">回复</Button>
</Anchor>
}
}
<span class="small ms-2">发布于: @Model.CreateTime.ToString("yyyy-MM-dd")</span>
</div>
</div>
</div>
<div>@Model.Content</div>
@{
if (Childs.HasItems())
{
//这里实现一个循环递归 渲染出树形结构
<ul class="list-unstyled mb-0 border-top-1 border-light">
@{
foreach (var msg in Childs)
{
<_DisplayCard Model="msg" @bind-AllDatas="AllDatas" OnReplyChanged="OnReplyChanged" ShowReply="ShowReply"></_DisplayCard>
}
}
</ul>
}
}
</div>
<hr class="m-0 border-light" />
</div>
</li>
- UI组件后端代码
@code {
/// <summary>
/// 传入当前级的留言
/// </summary>
/// <returns></returns>
[Parameter]
public GuestBook Model { get; set; }
/// <summary>
/// 传入当前级的留言包含的子留言
/// </summary>
/// <returns></returns>
private IEnumerable<GuestBook> Childs { get; set; }
/// <summary>
/// 本页对应的所有留言信息
/// </summary>
/// <returns></returns>
[Parameter]
public List<GuestBook> AllDatas { get; set; }
/// <summary>
/// 实现数据双向绑定
/// </summary>
/// <returns></returns>
[Parameter]
public EventCallback<List<GuestBook>> AllDatasChanged { get; set; }
[Parameter]
public bool ShowReply { get; set; }
protected override async Task OnParametersSetAsync()
{
if (AllDatas.HasItems())
{
Childs = AllDatas.Where(e => e.ParentId == Model.Id);
}
}
/// <summary>
/// 选择项目变化事件
/// </summary>
/// <returns></returns>
async Task OnSelectedItemsChangedAsync(GuestBook guestBook)
{
await OnReplyChanged.InvokeAsync(guestBook);
}
/// <summary>
/// 回复点选目标事件
/// </summary>
/// <returns></returns>
[Parameter]
public EventCallback<GuestBook> OnReplyChanged { get; set; }
}
实现留言板列表页(此处只列UI前端部分代码)
@{
if (this.LoginUser is not null)
{
<div class="container">
<div class="pt-3" id="anchor1">
<div class="mb-3">
@{
//ParentReplyMessage 对应要回复消息
if (ParentReplyMessage is not null)
{
<div class="row">
<div class="col">
<div class="alert alert-info p-2 border-0">
回复 @ParentReplyMessage.GuestUser.UserName @ParentReplyMessage.CreateTime.ToString("yyyy/MM/dd") : @ParentReplyMessage.Content
</div>
</div>
<div class="col-auto">
<Button Size="Size.ExtraSmall" OnClick="OnDismissAsync" Color="Color.Secondary"><iclass="fa fa-soild fa-trash"></i></Button>
</div>
</div>
}
}
<BootstrapInput @bind-Value="Content" IsTrim="true" IsAutoFocus="true" Clearable="true" PlaceHolder="输入留言内容"></BootstrapInput>
</div>
<div class="text-center mb-3">
<Button Size="Size.Small" OnClick="SubmitContentAsync" IsKeepDisabled="true"><i class="fa fa-soild fa-message me-1"></i>提交留言</Button>
</div>
</div>
<h6 class="fw-bold">网友留言:</h6>
<div class="mb-3">
@{
//ParentItems 对应第一级的留言列表
if (this.ParentItems.HasItems())
{
<ul class="list-unstyled mb-0">
@{
foreach (var msg in ParentItems)
{
<_DisplayCard Model="msg" @bind-AllDatas="AllDatas" OnReplyChanged="@((e)=>OnReplyChanged(e))" ShowReply="true"></_DisplayCard>
}
}
</ul>
} else {
<div class="text-center text-warning">
来都来了,要不留个言?
</div>
}
}
</div>
<div class="">
<!--分页组件-->
<Pagination PageCount="TotalPages" PageIndex="PageIndex" OnPageLinkClick="@((e)=>OnQueryAsync(e))" Alignment="Alignment.Center"></Pagination>
</div>
</div>
}
}
文章结束
代码本质上就是一个组件循环递归嵌套算法逻辑。
1. 文明上网,理性表达,营造舒适的学习氛围!
2. 反馈仅限本页主题相关,违法违规的无关内容一律无视