如何在 Blazor 客户端应用程序中使用 Bootstrap 模式?
How to use Bootstrap modal in Blazor client app?
我正在尝试显示 bootstrap 模式然后绑定其按钮。但是我无法通过显示模态的第一步。我正在使用 .net core 3.1 的 Blazor 客户端模板。我有一个名为 Modal.razor 的页面,其中包含我从 getbootstrap.com 中找到的 bootstrap 模式。
@if (Show)
{
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
}
@code {
[Parameter]
public bool Show { get; set; } = false;
}
我在 index.razor 文件中调用了模态
@page "/"
<button @onclick="(()=>switchModal=!switchModal)">Switch Modal</button>
<Modal Show="switchModal"/>
@code{
bool switchModal = false;
}
你可能会说应该在这里调用StateHasChanged。但是即使我复制并粘贴 index.razor 中的模态代码,我也看不到任何东西。
可能有更好的方法来执行此操作,但这里有一个可以帮助您入门的工作示例:
页数:
@page "/modal-test"
<BlazorApp1.Components.Modal @ref="Modal"></BlazorApp1.Components.Modal>
<button @onclick="() => Modal.Open()">Open Modal</button>
@code {
private BlazorApp1.Components.Modal Modal { get; set; }
}
组件:
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close()">Close</button>
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
public void Open()
{
ModalDisplay = "block;";
ModalClass = "Show";
ShowBackdrop = true;
StateHasChanged();
}
public void Close()
{
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
}
解决此问题的另一种选择是使用 JSInterop 调用 $('#modalId').modal()
您可以通过执行以下操作让组件的每个版本都有一个唯一的 ID:
<div id="bootstrap-modal-@Guid"
然后使用保存的 ID 以 jQuery.
调用 .modal()
基于 Kyle 的回答,这是我对 Blazor 的第一个实验:使模态对话框组件采用任何标记或组件。
Modal.razor
<div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
@Body
</div>
<div class="modal-footer">
@Footer
</div>
</div>
</div>
</div>
@if (showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Parameter]
public RenderFragment Title { get; set; }
[Parameter]
public RenderFragment Body { get; set; }
[Parameter]
public RenderFragment Footer { get; set; }
private string modalDisplay = "none;";
private string modalClass = "";
private bool showBackdrop = false;
public void Open()
{
modalDisplay = "block;";
modalClass = "show";
showBackdrop = true;
}
public void Close()
{
modalDisplay = "none";
modalClass = "";
showBackdrop = false;
}
}
Index.razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<button class="btn btn-primary" @onclick="() => modal.Open()">Modal!</button>
<Modal @ref="modal">
<Title>This is a <em>Title!</em></Title>
<Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Omnes enim iucundum motum, quo sensus hilaretur.
<i>Quis istud possit, inquit, negare?</i>
<mark>Ego vero isti, inquam, permitto.</mark> Duo Reges: constructio interrete.
</p>
<FetchData />
<dl>
<dt><dfn>Stoici scilicet.</dfn></dt>
<dd>An hoc usque quaque, aliter in vita?</dd>
<dt><dfn>Erat enim Polemonis.</dfn></dt>
<dd>Quod cum accidisset ut alter alterum necopinato videremus, surrexit statim.</dd>
</dl>
</Body>
<Footer>
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => modal.Close()">Close</button>
</Footer>
</Modal>
@code {
private Modal modal { get; set; }
}
同样基于 Kyle 的回答,如果您在显示和 class 调整之间放置一个短暂的延迟,您可以 维持 bootstrap 淡入淡出效果 。
@code {
...
public async Task OpenModal()
{
ModalDisplay = "block;";
await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation
ModalClass = "show";
StateHasChanged();
}
public async Task CloseModal()
{
ModalClass = "";
await Task.Delay(250);
ModalDisplay = "none;";
StateHasChanged();
}
}
我也将 ModalClass 和 ModalDisplay 变量应用到背景元素
<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>
相信bootstrap这样可以更好的识别触发动画的状态变化
只为背景阴影添加淡入淡出class:
<div class="modal fade @ModalClass" tabindex="-1" role="dialog"
style="display:@ModalDisplay">
Kyle 的组件运行良好,但有谁知道如何使用 jqueryUi draggable()/resizeable() 函数向 bootstrap 模态添加可拖动和可调整大小的功能?
我有这个 link 到一个纯 javascript 解决方案:DRAG AND RESIZE BOOTSTRAP MODAL 本质上调用模态 div 上的可调整大小和可拖动功能
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<script type="text/javascript">
$('.modal-content').resizable({
//alsoResize: ".modal-dialog",
minHeight: 300,
minWidth: 300
});
$('.modal-dialog').draggable();
</script>
我试过将此脚本添加到我的 _Host.cshtml 页面,但没有效果。如有任何关于如何执行此操作的建议,我们将不胜感激...
大卫
更新了答案
答案是在 OnAfterRenderAsync 重写中显式调用 javascript 函数以将 JQuery UI 函数应用于模式 div。
例如
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await jsRuntime.InvokeVoidAsync("setModalDraggableAndResizable");
await base.OnAfterRenderAsync(firstRender);
}
其中 setModalDraggableAndResizable
是 _Hosts.cshtml 中的一个 javascript 函数:
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<script type="text/javascript">
function setModalDraggableAndResizable() {
$('.modal-content').resizable({
//alsoResize: ".modal-dialog",
minHeight: 300,
minWidth: 300
});
$('.modal-dialog').draggable();
}
</script>
模态窗口现在可以拖动和调整大小了...
Modal example image
使用 Kyle 解决方案,当我单击背景时我的对话框不会关闭。
我看到是z-index的问题:模态div的z-index是1050,背景div是1040,这样我就没办法了点击我的背景。
我已将背景移动到对话框中 div 并添加到模态对话框中 div z-index > 1040
(ES: 1055)
我还在背景中添加了 data-dismiss="modal" @onclick="() => Close()"
div,现在它和“关闭”按钮一样有效。
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document" style="z-index:1055">
...
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show" data-dismiss="modal" @onclick="() => Close()"></div>
}
</div>
更新: 我已将此答案转换为可以找到的服务
我调整了 and 答案以支持我们心爱的 Alert
、Prompt
和 Confirm
来自 C# 和 JavaScript。在最新的 Blazor Server 版本中测试 Bootstrap 5.
ProjectName.Components.Modal.razor
@using Microsoft.JSInterop
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title w-100 text-center" style="padding-left:31px">@Title</h5>
<button type="button" class="close border-0 bg-white" data-dismiss="modal" aria-label="Close" @onclick="() => Close(true)">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body mx-auto text-center">
@Body
@if (MType == ModalType.Prompt){
<input type="text" class="form-control text-center my-2" @bind-value="PromptValue" style="max-width:400px"></input>
}
</div>
<div class="modal-footer justify-content-center">
@if (MType == ModalType.Prompt || MType == ModalType.Confirm)
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">OK</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(true)">Cancel</button>
}
else
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">Close</button>
}
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Inject] IJSRuntime JS { get; set; }
public enum ModalType
{
Alert,
Prompt,
Confirm
}
/// <summary>
/// (Optional) We can setup an instance of this .net object to call directly from JavaScript. See JavaScript Usage section.
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
JS.InvokeVoidAsync("MODAL.SetDotnetReference", DotNetObjectReference.Create(this));
}
private string Title { get; set; }
private string Body { get; set; }
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
private string PromptValue { get; set; }
private bool ConfirmValue { get; set; }
private ModalType MType { get; set; }
private List<string> MsgIds = new List<string>();
[JSInvokable("Show")]
public async Task<dynamic> Show(ModalType mType, string title, string body)
{
// The JavaScript call MODAL.DotNetReference.invokeMethodAsync is non-blocking
// This means multiple calls to show the modal using invokeMethodAsync will only show the modal once.
// We can solve this by making sure each message waits in line.
string msgId = Guid.NewGuid().ToString();
if (!MsgIds.Contains(msgId))
MsgIds.Add(msgId);
// If multiple messages are being processed, wait for this msgs turn.
while (MsgIds.Count > 1 && MsgIds.IndexOf(msgId) != 0)
await Task.Delay(250);
Title = title;
Body = body;
ModalDisplay = "block;";
ModalClass = "Show";
MType = mType;
ShowBackdrop = true;
StateHasChanged();
while (ShowBackdrop)
await Task.Delay(250);
switch(mType)
{
default:
case ModalType.Alert:
MsgIds.Remove(msgId);
return string.Empty;
case ModalType.Confirm:
bool confirmResponse = ConfirmValue;
MsgIds.Remove(msgId);
return confirmResponse;
case ModalType.Prompt:
string promptResponse = PromptValue;
MsgIds.Remove(msgId);
return promptResponse;
}
}
private void Close(bool isCancel)
{
// Determine returned values.
PromptValue = isCancel ? string.Empty : PromptValue;
ConfirmValue = isCancel ? false : true;
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
}
标记用法
<Modal @ref="Modal"></Modal>
<button @onclick='() => Modal.Show(Modal.ModalType.Alert, "Title goes here","Body goes here")'>Open Modal</button>
代码用法
if (await Modal.Show(Modal.ModalType.Confirm,"Save Settings", "Are you sure you want to save settings?"))
{
string fileName = await Modal.Show(Modal.ModalType.Prompt, "File Name", "Please enter a filename");
if (!string.IsNullOrEmpty(fileName))
await Modal.Show(Modal.ModalType.Alert, "File Saved", $"File Saved as {fileName}");
}
JavaScript 用法
借助 promise 支持,我们可以直接从 JavaScript 获得 Prompt
和 Confirm
的响应。为了避免将我们的 Modal
声明为静态的,我们需要设置一个 DotNetReference
.
// Defined somewhere globally
var MODAL = {};
MODAL.DotNetReference = null;
MODAL.SetDotnetReference = function (pDotNetReference) {
MODAL.DotNetReference = pDotNetReference;
};
MODAL.MType = {
Alert: 0,
Prompt:1,
Confirm: 2,
};
// Called from wherever
MODAL.DotNetReference.invokeMethodAsync('Show', MODAL.MType.Prompt, `Title goes here`, `Body goes here`)
.then(data => {
console.log(`Prompt Response`, data);
});
JavaScript 注意:建议使用 Polyfil 以在旧版浏览器中提供 promise 支持
作为替代方案,您可以使用 Bootstrap Blazor,它是 open-source 的 bootstrap 与 blazor 集成的非常好的实现。
我正在尝试显示 bootstrap 模式然后绑定其按钮。但是我无法通过显示模态的第一步。我正在使用 .net core 3.1 的 Blazor 客户端模板。我有一个名为 Modal.razor 的页面,其中包含我从 getbootstrap.com 中找到的 bootstrap 模式。
@if (Show)
{
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
}
@code {
[Parameter]
public bool Show { get; set; } = false;
}
我在 index.razor 文件中调用了模态
@page "/"
<button @onclick="(()=>switchModal=!switchModal)">Switch Modal</button>
<Modal Show="switchModal"/>
@code{
bool switchModal = false;
}
你可能会说应该在这里调用StateHasChanged。但是即使我复制并粘贴 index.razor 中的模态代码,我也看不到任何东西。
可能有更好的方法来执行此操作,但这里有一个可以帮助您入门的工作示例:
页数:
@page "/modal-test"
<BlazorApp1.Components.Modal @ref="Modal"></BlazorApp1.Components.Modal>
<button @onclick="() => Modal.Open()">Open Modal</button>
@code {
private BlazorApp1.Components.Modal Modal { get; set; }
}
组件:
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close()">Close</button>
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
public void Open()
{
ModalDisplay = "block;";
ModalClass = "Show";
ShowBackdrop = true;
StateHasChanged();
}
public void Close()
{
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
}
解决此问题的另一种选择是使用 JSInterop 调用 $('#modalId').modal()
您可以通过执行以下操作让组件的每个版本都有一个唯一的 ID:
<div id="bootstrap-modal-@Guid"
然后使用保存的 ID 以 jQuery.
基于 Kyle 的回答,这是我对 Blazor 的第一个实验:使模态对话框组件采用任何标记或组件。
Modal.razor
<div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
@Body
</div>
<div class="modal-footer">
@Footer
</div>
</div>
</div>
</div>
@if (showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Parameter]
public RenderFragment Title { get; set; }
[Parameter]
public RenderFragment Body { get; set; }
[Parameter]
public RenderFragment Footer { get; set; }
private string modalDisplay = "none;";
private string modalClass = "";
private bool showBackdrop = false;
public void Open()
{
modalDisplay = "block;";
modalClass = "show";
showBackdrop = true;
}
public void Close()
{
modalDisplay = "none";
modalClass = "";
showBackdrop = false;
}
}
Index.razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<button class="btn btn-primary" @onclick="() => modal.Open()">Modal!</button>
<Modal @ref="modal">
<Title>This is a <em>Title!</em></Title>
<Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Omnes enim iucundum motum, quo sensus hilaretur.
<i>Quis istud possit, inquit, negare?</i>
<mark>Ego vero isti, inquam, permitto.</mark> Duo Reges: constructio interrete.
</p>
<FetchData />
<dl>
<dt><dfn>Stoici scilicet.</dfn></dt>
<dd>An hoc usque quaque, aliter in vita?</dd>
<dt><dfn>Erat enim Polemonis.</dfn></dt>
<dd>Quod cum accidisset ut alter alterum necopinato videremus, surrexit statim.</dd>
</dl>
</Body>
<Footer>
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => modal.Close()">Close</button>
</Footer>
</Modal>
@code {
private Modal modal { get; set; }
}
同样基于 Kyle 的回答,如果您在显示和 class 调整之间放置一个短暂的延迟,您可以 维持 bootstrap 淡入淡出效果 。
@code {
...
public async Task OpenModal()
{
ModalDisplay = "block;";
await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation
ModalClass = "show";
StateHasChanged();
}
public async Task CloseModal()
{
ModalClass = "";
await Task.Delay(250);
ModalDisplay = "none;";
StateHasChanged();
}
}
我也将 ModalClass 和 ModalDisplay 变量应用到背景元素
<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>
相信bootstrap这样可以更好的识别触发动画的状态变化
只为背景阴影添加淡入淡出class:
<div class="modal fade @ModalClass" tabindex="-1" role="dialog"
style="display:@ModalDisplay">
Kyle 的组件运行良好,但有谁知道如何使用 jqueryUi draggable()/resizeable() 函数向 bootstrap 模态添加可拖动和可调整大小的功能?
我有这个 link 到一个纯 javascript 解决方案:DRAG AND RESIZE BOOTSTRAP MODAL 本质上调用模态 div 上的可调整大小和可拖动功能
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<script type="text/javascript">
$('.modal-content').resizable({
//alsoResize: ".modal-dialog",
minHeight: 300,
minWidth: 300
});
$('.modal-dialog').draggable();
</script>
我试过将此脚本添加到我的 _Host.cshtml 页面,但没有效果。如有任何关于如何执行此操作的建议,我们将不胜感激...
大卫
更新了答案
答案是在 OnAfterRenderAsync 重写中显式调用 javascript 函数以将 JQuery UI 函数应用于模式 div。
例如
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await jsRuntime.InvokeVoidAsync("setModalDraggableAndResizable");
await base.OnAfterRenderAsync(firstRender);
}
其中 setModalDraggableAndResizable
是 _Hosts.cshtml 中的一个 javascript 函数:
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<script type="text/javascript">
function setModalDraggableAndResizable() {
$('.modal-content').resizable({
//alsoResize: ".modal-dialog",
minHeight: 300,
minWidth: 300
});
$('.modal-dialog').draggable();
}
</script>
模态窗口现在可以拖动和调整大小了...
Modal example image
使用 Kyle 解决方案,当我单击背景时我的对话框不会关闭。
我看到是z-index的问题:模态div的z-index是1050,背景div是1040,这样我就没办法了点击我的背景。
我已将背景移动到对话框中 div 并添加到模态对话框中 div z-index > 1040
(ES: 1055)
我还在背景中添加了 data-dismiss="modal" @onclick="() => Close()"
div,现在它和“关闭”按钮一样有效。
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document" style="z-index:1055">
...
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show" data-dismiss="modal" @onclick="() => Close()"></div>
}
</div>
更新: 我已将此答案转换为可以找到的服务
我调整了 Alert
、Prompt
和 Confirm
来自 C# 和 JavaScript。在最新的 Blazor Server 版本中测试 Bootstrap 5.
ProjectName.Components.Modal.razor
@using Microsoft.JSInterop
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title w-100 text-center" style="padding-left:31px">@Title</h5>
<button type="button" class="close border-0 bg-white" data-dismiss="modal" aria-label="Close" @onclick="() => Close(true)">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body mx-auto text-center">
@Body
@if (MType == ModalType.Prompt){
<input type="text" class="form-control text-center my-2" @bind-value="PromptValue" style="max-width:400px"></input>
}
</div>
<div class="modal-footer justify-content-center">
@if (MType == ModalType.Prompt || MType == ModalType.Confirm)
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">OK</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(true)">Cancel</button>
}
else
{
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">Close</button>
}
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Inject] IJSRuntime JS { get; set; }
public enum ModalType
{
Alert,
Prompt,
Confirm
}
/// <summary>
/// (Optional) We can setup an instance of this .net object to call directly from JavaScript. See JavaScript Usage section.
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
JS.InvokeVoidAsync("MODAL.SetDotnetReference", DotNetObjectReference.Create(this));
}
private string Title { get; set; }
private string Body { get; set; }
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
private string PromptValue { get; set; }
private bool ConfirmValue { get; set; }
private ModalType MType { get; set; }
private List<string> MsgIds = new List<string>();
[JSInvokable("Show")]
public async Task<dynamic> Show(ModalType mType, string title, string body)
{
// The JavaScript call MODAL.DotNetReference.invokeMethodAsync is non-blocking
// This means multiple calls to show the modal using invokeMethodAsync will only show the modal once.
// We can solve this by making sure each message waits in line.
string msgId = Guid.NewGuid().ToString();
if (!MsgIds.Contains(msgId))
MsgIds.Add(msgId);
// If multiple messages are being processed, wait for this msgs turn.
while (MsgIds.Count > 1 && MsgIds.IndexOf(msgId) != 0)
await Task.Delay(250);
Title = title;
Body = body;
ModalDisplay = "block;";
ModalClass = "Show";
MType = mType;
ShowBackdrop = true;
StateHasChanged();
while (ShowBackdrop)
await Task.Delay(250);
switch(mType)
{
default:
case ModalType.Alert:
MsgIds.Remove(msgId);
return string.Empty;
case ModalType.Confirm:
bool confirmResponse = ConfirmValue;
MsgIds.Remove(msgId);
return confirmResponse;
case ModalType.Prompt:
string promptResponse = PromptValue;
MsgIds.Remove(msgId);
return promptResponse;
}
}
private void Close(bool isCancel)
{
// Determine returned values.
PromptValue = isCancel ? string.Empty : PromptValue;
ConfirmValue = isCancel ? false : true;
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
}
标记用法
<Modal @ref="Modal"></Modal>
<button @onclick='() => Modal.Show(Modal.ModalType.Alert, "Title goes here","Body goes here")'>Open Modal</button>
代码用法
if (await Modal.Show(Modal.ModalType.Confirm,"Save Settings", "Are you sure you want to save settings?"))
{
string fileName = await Modal.Show(Modal.ModalType.Prompt, "File Name", "Please enter a filename");
if (!string.IsNullOrEmpty(fileName))
await Modal.Show(Modal.ModalType.Alert, "File Saved", $"File Saved as {fileName}");
}
JavaScript 用法
借助 promise 支持,我们可以直接从 JavaScript 获得 Prompt
和 Confirm
的响应。为了避免将我们的 Modal
声明为静态的,我们需要设置一个 DotNetReference
.
// Defined somewhere globally
var MODAL = {};
MODAL.DotNetReference = null;
MODAL.SetDotnetReference = function (pDotNetReference) {
MODAL.DotNetReference = pDotNetReference;
};
MODAL.MType = {
Alert: 0,
Prompt:1,
Confirm: 2,
};
// Called from wherever
MODAL.DotNetReference.invokeMethodAsync('Show', MODAL.MType.Prompt, `Title goes here`, `Body goes here`)
.then(data => {
console.log(`Prompt Response`, data);
});
JavaScript 注意:建议使用 Polyfil 以在旧版浏览器中提供 promise 支持
作为替代方案,您可以使用 Bootstrap Blazor,它是 open-source 的 bootstrap 与 blazor 集成的非常好的实现。