1

我最近开始使用 Blazor,发现它是一项非常有前途的技术。

我正在制作自定义嵌套 Blazor 组件,但我似乎并没有让它按我想要的方式工作。

目标是拥有一个具有“ContentHeader”和“ContentBody”属性的“Content”组件。但是,“ContentHeader”应该是另一个具有“Title”和“ActionBar”属性的自定义组件。所需的用法如下:

<Content>
    <ContentHeader>        
        <Title>
            Title
        </Title>        
        <ActionBar>
            <button>Test button</button>
        </ActionBar>
    </ContentHeader>
    <ContentBody>
        Body
    </ContentBody>
</Content>

“内容”组件:

<CascadingValue Value="this">
    <div class="content-container">
        @ContentHeader(Header)
        <div class="content-body">
            @ContentBody
        </div>
    </div>
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment<ContentHeader> ContentHeader { get; set; }

    [Parameter]
    public RenderFragment ContentBody { get; set; }

    public ContentHeader Header { get; set; }

    public async Task SetContentHeader(ContentHeader contentHeader)
    {
        Header = contentHeader;
        await InvokeAsync(StateHasChanged);
    }
}

“ContentHeader”组件:

<div class="content-header">
    <h3>@Title</h3>
    <div class="content-header-action-bar">
        @ActionBar
    </div>
</div>

@code {
    [CascadingParameter]
    public Content Content { get; set; }

    [Parameter]
    public RenderFragment Title { get; set; }

    [Parameter]
    public RenderFragment ActionBar { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await Content.SetContentHeader(this);
        await base.OnInitializedAsync();
    }
}

我得到的实际渲染输出是这样的:

<div class="content-container">
    <!--!-->
        Title
    <!--!-->        
    <!--!-->
    <button>Test button</button>
    <!--!-->
    <div class="content-body">
        <!--!-->
        Body
    </div>
</div>

似乎“ContentHeader”组件的标记被完全忽略了。<h3></h3>“HeaderComponent”标题周围的标签丢失,按钮未放置在里面<div class="content-header-action-bar"></div>

我还注意到OnInitializedAsync“ContentHeader”没有被触发。

我究竟做错了什么?我什至使用正确的方法吗?

提前谢谢了。

亲切的问候

4

1 回答 1

1

您尝试这样做的方式是不正确的,除非您将@ActionBar 呈现为您自己,我认为您没有尝试这样做。

这是来自我的开源项目 Blazor Chat:

来源: https ://github.com/DataJuggler/BlazorChat

实时站点:一次没有多少用户 https://blazorchat.com

这是我的索引页面。ScreenType 是一个枚举变量。

@if (ScreenType == ScreenTypeEnum.Join)
{ 
    <Join Parent=this></Join>
}
else if (ScreenType == ScreenTypeEnum.Login)
{
    <Login Parent=this></Login>
}
else
{
    <Chat Parent=this></Chat>
    @if (TextHelper.Exists(Message))
    {  
        <div class="message">
            @Message
        </div>
    }
}  

通过Parent=this,子组件和父组件和页面可以通过接口进行通信。我不打算在这里讨论,但如果有人好奇,这里是我大约六个月前写的一篇关于这个主题的博客文章:

https://datajugglerblazor.blogspot.com/2020/01/how-to-use-interfaces-to-communicate.html

我不能发布整个项目,但这里有一些相关部分,可能会帮助您更好地理解父/子组件。

这是一个组件项目中的示例,有多个子组件:

聊天剃须刀:

@if (HasUser)
{
    @if (Connected)
    {
        <div class="chatroom2">
            @if (ListHelper.HasOneOrMoreItems(Messages))
            {
                foreach (SubscriberMessage message in Messages)
                {
                    <SpeechBubble Message=message>
                    </SpeechBubble>
                }
            }
        </div>
        <div class="whoseonlist">            
            @if (ListHelper.HasOneOrMoreItems(Names))
            {  
                @foreach (SubscriberCallback callback in Names)
                {
                    <button class="listbutton" @onclick="(Action<EventArgs>) (args => 
SendPrivateMessageClicked(args, callback.Id))">@callback.Name</button><br />
                }
            }
            <textarea class="typedtext" @bind="MessageText"></textarea>
            <button class="greenbutton8" 
@onclick="BroadCastMessage">Broadcast</button>
            <div class="privatemessageinfo">
                Click a name to send<br />a private message.
            </div>
        </div> 
    }
    else
    { 
        <div id="ChatRoom" class="chatroom">
            <div class="moveup4">
                Enter Chat<br />
                <input type="text" @bind="SubscriberName" /><br />
                <button class="greenbutton6" 
@onclick="@RegisterWithServer">Connect</button>
            </div>
        </div>    
    }
}
else
{
    <div class="loginorjointochat">
    </div>
}

如果您确实想要呈现 HTML,则语音气泡有一个 message 属性,它会清理 HTML。因此,如果用户输入,我发现这个很酷的网站https://pixeldatabase.net(我的网站),经过消毒的代码呈现为超链接(我进行文本替换并将其变成锚标记),而且如果消息包含粗体标记,则文本呈现为粗体,或者 HTML 换行符用于分隔行等。

foreach (SubscriberMessage message in Messages)
{
    <SpeechBubble Message=message>
    </SpeechBubble>
}

这要归功于这个 Nuget 包:HtmlSanitizer

它的参考是 Ganss.XSS,我花了一段时间才弄明白。

如果有人想要,这是一个带有扩展方法的类:

using Ganss.XSS;
using Microsoft.AspNetCore.Components;

namespace BlazorChat
{
    public static class MarkupStringExtensions
    {
        public static MarkupString Sanitize(this MarkupString markupString)
        {
            return new MarkupString(SanitizeInput(markupString.Value));
        }

        private static string SanitizeInput(string value)
        {
            var sanitizer = new HtmlSanitizer();
            return sanitizer.Sanitize(value);
        }
    }
}

这是呈现的 HTML 文本的屏幕截图:

在此处输入图像描述

于 2020-07-26T21:37:15.863 回答