使用C#方法在Blazor中创建弹出窗口

3

我有一个简单的页面index.razor,其中包含一个按钮:

<a class="btn btn-login" @onclick="RedirectPage" >Log in</a>

<div
    @bind-Visible="@InvalidLogin"
    BodyText="Error">
</div>

@code{
    InvalidLogin {get; set;} = false;
}

在函数RedirectPage中检查值是否有效。如果无效,我想要一个弹出窗口提供信息:

private void RedirectPage
{
    this.InvalidLogin = true;
}

这个函数在 index.razor.cs 中,并且已经使用正确的命名空间添加了 @using
我该如何创建它,使得每当按钮被点击时都会弹出一个弹窗?

当你说“popup”时,你是指模态对话框吗?如果是这样,你使用的是哪个CSS框架?如果是这样,请查看这个答案和我的答案,https://dev59.com/Dbj4oIgBc1ULPQZFLZaf#71888010 - MrC aka Shaun Curtis
了解在客户端,弹出窗口只是一个被样式化为出现在其他元素前面的div或其他元素。实现这一点的一种非常简单的方法是在您的布局页面中放置一个div。您可以使用“this”关键字将您的布局页面传递给所有子页面,然后使用布局页面上的方法来更改弹出窗口元素的CSS类。 - Bennyboy1973
3个回答

11
你可以创建一个简单的弹出窗口(或模态对话框)组件。下面,我写了一个使用 Bootstrap 5 toast 组件的示例弹出窗口 Razor 组件。
Popup.razor 文件
@{
    var showClass = IsVisible ? "d-block" : "d-none";
}

<div class="toast-container p-3 @showClass" data-bs-autohide="true" data-bs-delay="5000">
    <div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-header">
            <strong class="me-auto">@HeaderText</strong>
            <button type="button" class="btn-close" aria-label="Close" @onclick="Close"></button>
        </div>

        <div class="toast-body">
            @BodyText
        </div>
    </div>
</div>

@code {
    [Parameter]
    public bool IsVisible { get; set; }

    [Parameter]
    public EventCallback<bool> IsVisibleChanged { get; set; }

    [Parameter]
    public string? HeaderText { get; set; }

    [Parameter]
    public string? BodyText { get; set; }

    public void Show(string bodyText, string headerText = "")
    {
        HeaderText = headerText;
        BodyText = bodyText;
        IsVisible = true;
        StateHasChanged();
    }

    private void Close()
    {
        HeaderText = string.Empty;
        BodyText = string.Empty;
        IsVisible = false;
        StateHasChanged();
    }
}

在你的代码中使用Popup Razor 组件:

<a class="btn btn-login" @onclick="RedirectPage" >Log in</a>

<Popup @ref="popupRef" />

@code{
    private Popup popupRef;
    
    private void RedirectPage()
    {
        // Shows the popup at the center of the screen
        popupRef.Show("Popup body text");
    }
}

2
谢谢,我做了一些更改,现在它可以工作了。 - B.Quaink

4
如何在没有第三方库的情况下创建对话框。 我必须使用最少量的js,因为新的HTML5 <dialog...元素只能通过.showModal()而不是通过操作属性来以对话框模式打开。 wwwroot/scripts/dialogJsInteropt.js
export function showDialog(element, parm) {
    return element.showModal();
}

export function closeDialog(element, parm) {
    return element.close();
}

Dialog.razor

<CascadingValue Value=@this IsFixed=true >
    <dialog @ref="@dialogElement" @attributes=@CapturedAttributes>
    @if(visible)
    {
        @ChildContent
    }
    </dialog>
</CascadingValue>

Dialog.razor.cs

public partial class Dialog : ComponentBase, IAsyncDisposable
{
    private readonly Lazy<Task<IJSObjectReference>> moduleTask;
    private ElementReference dialogElement;
    private bool visible = false;

    public Dialog()
    {
        moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>(
            identifier: "import",
            args: "./scripts/dialogJsInterop.js")
        .AsTask());
    }

    [Inject]
    private IJSRuntime jsRuntime { get; set; }

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

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> CapturedAttributes { get; set; }

    public async ValueTask ShowDialogAsync()
    {
        var module = await moduleTask.Value;
        await module.InvokeVoidAsync("showDialog", dialogElement);
        visible = true;
    }

    public async ValueTask CloseDialogAsync()
    {
        var module = await moduleTask.Value;
        await module.InvokeVoidAsync("closeDialog", dialogElement);
        visible = false;
    }

    public async ValueTask DisposeAsync()
    {
        if (moduleTask.IsValueCreated)
        {
            var module = await moduleTask.Value;
            await module.DisposeAsync();
        }
    }
}

目前您拥有一个可用的对话框。

我添加了以下组件以使其更加方便。 注意:从现在开始,我会使用 Bootstrap 进行样式设计,这很容易更改为 Tailwind。

DialogCloseButton.razor

<button @attributes=CapturedAttributes @onclick=@CloseDialog />

DialogCloseButton.razor.cs

public partial class DialogCloseButton : ComponentBase
{
    [CascadingParameter]
    public Dialog Dialog { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> CapturedAttributes { get; set; } = new Dictionary<string, object>
    {
        { "class", "btn btn-close" }
    };

    private async Task CloseDialog() => await Dialog.CloseDialogAsync();
}

DialogCloseButton.razor.css

.btn:focus {
    box-shadow: none;
}

DialogLayout.razor

<div class="d-flex flex-row justify-content-between border-bottom border-1">
    <div class="flex-fill p-1 ps-3 fw-bolder user-select-none app-gradient text-white">
        @Header
    </div>
    <div class="p-1">
        <DialogCloseButton />
    </div>
</div>
<div class="p-3">
    @Content
</div>

DialogLayout.razor.cs

public partial class DialogLayout
{
    [Parameter]
    public RenderFragment Header { get; set; }

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

用法:

<Dialog @ref=@dialog class="p-0 border rounded shadow">
    <DialogLayout>
        <Header>
           <MessagesIcon Size=16 /> Add Message
        </Header>
        <Content>
            <MessageFormView />
        </Content>
    </DialogLayout>
</Dialog>
<button class="btn btn-outline-success" @onclick=@OpenDialog>Add Message</button>
@code {
    private Dialog dialog;

    ...

    private async Task OpenDialog() => await dialog.ShowDialogAsync();
}

2
这是一个非常简单的例子,展示了您提出的要求(我将所有内容放在index.razor文件中,但您可以使用CSS隔离和专用的.cs文件来处理@code{}中的所有内容。
@page "/index"
<style>
    .active {
        display: block;
    }
    .inactive {
        display: none;
    }
</style>

<a class="btn btn-login" @onclick="RedirectPage" >Log in</a>

<div class="@PopupClass">
    Error: @ErrorText
</div>

@code{
    bool InvalidLogin {get; set;} = false;

    string PopupClass => InvalidLogin ? "active" : "inactive";
    public string ErrorText { get; set; } = "Example of exception";

    private void RedirectPage()
    {
        this.InvalidLogin = !this.InvalidLogin;
    }
}

当然,您需要适当地利用这个例子来实现更具体的业务逻辑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接