基于BootstrapBlazor实现一个用户评论留言板组件效果

Blazor
45
Blazor
网页评论互动
文章评论组件
Blazor留言板
Blazor评论
BootstrapBlazor
网页评论

这两天给往网站文章做了个留言板功能,本意是一方面可以给一些网友提供一些帮助,另一方面给网页内容做一些补充,实现了基本的评论嵌套回复功能,还做了后台审核功能。 由于个人网站的备案性质不允许挂评论留言板,所以上线了短暂10分钟后突然意识到不能上就自己默默的下掉了留言互动模块。 但毕竟也是花了不少时间码出来的,所以这里把留言板实现的核心代码部分分享出来(基于blazor实现效果简直不要太简单)

先展示一下效果图 理论上可以多级树状展示

尝试用Blazor实现一个用户评论留言板组件效果

数据库表字段设计部分

字段名称 描述
Id 消息Id
TargetUrl 目标网页地址
Content 用户留言内容
UserId 用户Id对应用户系统
ParentId 父级消息Id(默认为1楼)

C#实体部分 (这部分代码用到Freesql作为数据库orm)

public class GuestBook 
{
    /// 
    /// 消息Id 
    /// 
    public Guid Id { get; set; }
    /// 
    /// 目标网页地址
    /// 
    public string TargetUrl { get; set; }
    /// 
    /// 留言内容
    /// 
    public string Content { get; set; }
    /// 
    /// 发言用户Id
    /// 
    public Guid UserId { get; set; }
    /// 
    /// 用户信息(参考Freesql Navigate导航属性)
    /// 
    [Navigate(nameof(UserId))]
     public UserMember GuestUser { get; set; }
     /// 
     /// 关联父级别消息(即回复目标)
     /// 
     public Guid ParentId { get; set; } = Guid.Empty;
}

写一个用户评论的UI组件 核心在于实现一个递归UI子组件

(这里用了 Bootstrap Blazor UI)

  1. 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.Contentdiv>
            @{
                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">
                            }
                        }
                   ul>
                }
            }
      div>
	  <hr class="m-0 border-light" />
  div>
li>
  1. UI组件后端代码
@code {
	/// 
	/// 传入当前级的留言
	/// 
	/// 
	[Parameter]
 	public GuestBook Model { get; set; }
	/// 
	/// 传入当前级的留言包含的子留言
	/// 
	/// 
	private IEnumerable Childs { get; set; }
    /// 
	/// 本页对应的所有留言信息
	/// 
	/// 
	[Parameter]
	public List AllDatas { get; set; }
	/// 
	/// 实现数据双向绑定
	/// 
	/// 
    [Parameter]
    public EventCallback> 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);
		}
	}
	/// 
	/// 选择项目变化事件
	/// 
	/// 
	async Task OnSelectedItemsChangedAsync(GuestBook guestBook)
	{
		await OnReplyChanged.InvokeAsync(guestBook);
	}
	/// 
	/// 回复点选目标事件
	/// 
	/// 
	[Parameter]
	public EventCallback 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">i>Button>
							div>
						div>
					}
				}
	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">
				}
			}
			ul>
		} else {
				<div class="text-center text-warning">
 					来都来了,要不留个言?
				div>
			  	}
		}
		div>
		
<Pagination PageCount="TotalPages" PageIndex="PageIndex" OnPageLinkClick="@((e)=>OnQueryAsync(e))" Alignment="Alignment.Center">Pagination> div> div> } }

文章结束

代码本质上就是一个组件循环递归嵌套算法逻辑。

历时半个月博客程序升级到BlazorAuto后网站性能反而下降了
Blazor页面嵌入子组件传入中文文本会被转义成Unicode字符的解决办法
个人使用Blazor与BootstrapBlazor重构网站的开发体验太棒了
微软系列Blazor开源Web框架入门学习到放弃
暂无相关内容...
暂无相关内容...
免责声明 部分转载分享内容若侵犯您的权益,还请 邮件联系 侵删