首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有自定义子组件的自定义Blazor组件

具有自定义子组件的自定义Blazor组件
EN

Stack Overflow用户
提问于 2020-07-27 01:40:48
回答 1查看 2.1K关注 0票数 1

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

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

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

代码语言:javascript
复制
<Content>
    <ContentHeader>        
        <Title>
            Title
        </Title>        
        <ActionBar>
            <button>Test button</button>
        </ActionBar>
    </ContentHeader>
    <ContentBody>
        Body
    </ContentBody>
</Content>

Content组件:

代码语言:javascript
复制
<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“组件:

代码语言:javascript
复制
<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();
    }
}

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

代码语言:javascript
复制
<div class="content-container">
    <!--!-->
        Title
    <!--!-->        
    <!--!-->
    <button>Test button</button>
    <!--!-->
    <div class="content-body">
        <!--!-->
        Body
    </div>
</div>

似乎"ContentHeader“组件的标记被完全忽略了。缺少"HeaderComponent“标题周围的<h3></h3>标记,并且该按钮未放置在<div class="content-header-action-bar"></div>

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

我做错了什么?我用的是正确的方法吗?

在此之前,非常感谢您。

亲切的问候

EN

回答 1

Stack Overflow用户

发布于 2020-07-27 05:37:16

你尝试这样做的方式是不正确的,除非你正在呈现你自己的@ActionBar,而我认为你并没有试图这样做。

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

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

Live Site:没有多少用户同时访问https://blazorchat.com

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

代码语言:javascript
复制
@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

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

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

Chat.razor:

代码语言:javascript
复制
@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换行符用于分行,等等。

代码语言:javascript
复制
foreach (SubscriberMessage message in Messages)
{
    <SpeechBubble Message=message>
    </SpeechBubble>
}

这要归功于Nuget包: HtmlSanitizer

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

下面是一个带有扩展方法的类,如果有人需要的话:

代码语言:javascript
复制
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文本的屏幕截图:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63103591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档