Skip to content

Commit bd404f7

Browse files
authored
feat(Toast): support async update content use same option (#6037)
* doc: 重构代码 * doc: 更新参数说明文档 * refactor: 移除不使用的服务 * doc: 增加线程阻塞通知示例 * feat: 增加 Toast 更新脚本 * refactor: 代码优化 * refactor: 支持内容动态更新逻辑 * doc: 增加多语言支持 * refactor: 修复示例 * doc: 更新示例代码
1 parent 2fec2d0 commit bd404f7

File tree

7 files changed

+103
-26
lines changed

7 files changed

+103
-26
lines changed

src/BootstrapBlazor.Server/Components/Samples/Toasts.razor

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@page "/toast"
22
@inject IStringLocalizer<Toasts> Localizer
33
@inject ToastService ToastService
4-
@inject IJSRuntime JSRuntime
54

65
<h3>@Localizer["ToastsTitle"]</h3>
76

@@ -51,6 +50,10 @@ private ToastService? ToastService { get; set; }
5150
<Button Icon="fa-solid fa-triangle-exclamation" OnClick="@OnPreventClick" Text="@Localizer["ToastsPreventText"]"></Button>
5251
</DemoBlock>
5352

53+
<DemoBlock Title="@Localizer["ToastsAsyncTitle"]" Introduction="@Localizer["ToastsAsyncIntro"]" Name="Async" ShowCode="false">
54+
<Button IsAsync="true" Icon="fa-solid fa-triangle-exclamation" OnClick="@OnAsyncClick" Text="@Localizer["ToastsAsyncText"]"></Button>
55+
</DemoBlock>
56+
5457
<DemoBlock Title="@Localizer["ToastsCloseTitle"]" Introduction="@Localizer["ToastsCloseIntro"]" Name="Close" ShowCode="false">
5558
<Button Icon="fa-solid fa-triangle-exclamation" OnClick="@OnNotAutoHideClick" Text="@Localizer["ToastsCloseNotificationText"]"></Button>
5659
<ConsoleLogger @ref="Logger"></ConsoleLogger>

src/BootstrapBlazor.Server/Components/Samples/Toasts.razor.cs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ public sealed partial class Toasts
3737
[Inject, NotNull]
3838
private IOptions<BootstrapBlazorOptions>? Options { get; set; }
3939

40-
private int _delayTs => Options.Value.ToastDelay / 1000;
40+
private int DelayTs => Options.Value.ToastDelay / 1000;
41+
42+
private readonly ToastOption _option = new();
4143

4244
/// <summary>
4345
/// OnInitialized
@@ -46,10 +48,10 @@ protected override void OnInitialized()
4648
{
4749
base.OnInitialized();
4850

49-
Options1 = new ToastOption { Title = "Save data", IsAutoHide = false, Content = $"Save data successfully, automatically close after {_delayTs} seconds" };
50-
Options2 = new ToastOption { Category = ToastCategory.Error, Title = "Save data", IsAutoHide = false, Content = $"Save data successfully, automatically close after {_delayTs} seconds" };
51-
Options3 = new ToastOption { Category = ToastCategory.Information, Title = "Prompt information", IsAutoHide = false, Content = $"Information prompt pop-up window, automatically closes after {_delayTs} seconds" };
52-
Options4 = new ToastOption { Category = ToastCategory.Warning, Title = "Warning message", IsAutoHide = false, Content = $"Information prompt pop-up window, automatically closes after {_delayTs} seconds" };
51+
Options1 = new ToastOption { Title = "Save data", IsAutoHide = false, Content = $"Save data successfully, automatically close after {DelayTs} seconds" };
52+
Options2 = new ToastOption { Category = ToastCategory.Error, Title = "Save data", IsAutoHide = false, Content = $"Save data successfully, automatically close after {DelayTs} seconds" };
53+
Options3 = new ToastOption { Category = ToastCategory.Information, Title = "Prompt information", IsAutoHide = false, Content = $"Information prompt pop-up window, automatically closes after {DelayTs} seconds" };
54+
Options4 = new ToastOption { Category = ToastCategory.Warning, Title = "Warning message", IsAutoHide = false, Content = $"Information prompt pop-up window, automatically closes after {DelayTs} seconds" };
5355

5456
ToastContainer = Root.ToastContainer;
5557
}
@@ -62,18 +64,41 @@ await ToastService.Show(new ToastOption()
6264
PreventDuplicates = true,
6365
Category = ToastCategory.Success,
6466
Title = "Successfully saved",
65-
Content = $"Save data successfully, automatically close after {_delayTs} seconds"
67+
Content = $"Save data successfully, automatically close after {DelayTs} seconds"
6668
});
6769
}
6870

71+
private async Task OnAsyncClick()
72+
{
73+
_option.Title = Localizer["ToastsAsyncDemoTitle"];
74+
_option.ForceDelay = true;
75+
_option.IsAutoHide = false;
76+
_option.Delay = 3000;
77+
_option.Content = Localizer["ToastsAsyncDemoStep1Text"];
78+
_option.Category = ToastCategory.Information;
79+
await ToastService.Show(_option);
80+
81+
await Task.Delay(3000);
82+
_option.Content = Localizer["ToastsAsyncDemoStep2Text"];
83+
_option.IsAutoHide = true;
84+
_option.Category = ToastCategory.Information;
85+
await ToastService.Show(_option);
86+
87+
await Task.Delay(2000);
88+
_option.Content = Localizer["ToastsAsyncDemoStep3Text"];
89+
_option.Category = ToastCategory.Success;
90+
91+
await ToastService.Show(_option);
92+
}
93+
6994
private async Task OnSuccessClick()
7095
{
7196
ToastContainer.SetPlacement(Placement.BottomEnd);
7297
await ToastService.Show(new ToastOption()
7398
{
7499
Category = ToastCategory.Success,
75100
Title = "Successfully saved",
76-
Content = $"Save data successfully, automatically close after {_delayTs} seconds"
101+
Content = $"Save data successfully, automatically close after {DelayTs} seconds"
77102
});
78103
}
79104

@@ -84,7 +109,7 @@ await ToastService.Show(new ToastOption()
84109
{
85110
Category = ToastCategory.Error,
86111
Title = "Failed to save",
87-
Content = $"Failed to save data, automatically closes after {_delayTs} seconds"
112+
Content = $"Failed to save data, automatically closes after {DelayTs} seconds"
88113
});
89114
}
90115

@@ -95,7 +120,7 @@ await ToastService.Show(new ToastOption()
95120
{
96121
Category = ToastCategory.Information,
97122
Title = "Notification",
98-
Content = $"The system adds new components, it will automatically shut down after {_delayTs} seconds"
123+
Content = $"The system adds new components, it will automatically shut down after {DelayTs} seconds"
99124
});
100125
}
101126

@@ -106,7 +131,7 @@ await ToastService.Show(new ToastOption()
106131
{
107132
Category = ToastCategory.Warning,
108133
Title = "Warning",
109-
Content = $"If the system finds abnormality, please deal with it in time, and it will automatically shut down after {_delayTs} seconds"
134+
Content = $"If the system finds abnormality, please deal with it in time, and it will automatically shut down after {DelayTs} seconds"
110135
});
111136
}
112137

@@ -135,7 +160,7 @@ await ToastService.Show(new ToastOption()
135160
{
136161
Category = ToastCategory.Warning,
137162
ShowHeader = false,
138-
Content = $"The system adds new components, it will automatically shut down after {_delayTs} seconds"
163+
Content = $"The system adds new components, it will automatically shut down after {DelayTs} seconds"
139164
});
140165
}
141166

@@ -146,7 +171,7 @@ await ToastService.Show(new ToastOption()
146171
{
147172
Category = ToastCategory.Information,
148173
HeaderTemplate = RenderHeader,
149-
Content = $"The system adds new components, it will automatically shut down after {_delayTs} seconds"
174+
Content = $"The system adds new components, it will automatically shut down after {DelayTs} seconds"
150175
});
151176
}
152177

@@ -157,7 +182,7 @@ await ToastService.Show(new ToastOption()
157182
{
158183
Category = ToastCategory.Information,
159184
Title = "Notification",
160-
Content = $"<b>Toast</b> The component has changed position, it will automatically shut down after {_delayTs} seconds"
185+
Content = $"<b>Toast</b> The component has changed position, it will automatically shut down after {DelayTs} seconds"
161186
});
162187
}
163188

@@ -176,31 +201,31 @@ private AttributeItem[] GetAttributes() =>
176201
Name = "Title",
177202
Description = Localizer["ToastsAttrTitle"],
178203
Type = "string",
179-
ValueList = "",
204+
ValueList = "",
180205
DefaultValue = ""
181206
},
182207
new()
183208
{
184209
Name = "Content",
185210
Description = Localizer["ToastsAttrContent"],
186211
Type = "string",
187-
ValueList = "",
212+
ValueList = "",
188213
DefaultValue = ""
189214
},
190215
new()
191216
{
192217
Name = "Delay",
193218
Description = Localizer["ToastsAttrDelay"],
194219
Type = "int",
195-
ValueList = "",
220+
ValueList = "",
196221
DefaultValue = "4000"
197222
},
198223
new()
199224
{
200225
Name = "IsAutoHide",
201226
Description = Localizer["ToastsAttrIsAutoHide"],
202227
Type = "boolean",
203-
ValueList = "",
228+
ValueList = "",
204229
DefaultValue = "true"
205230
},
206231
new()

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,14 @@
124124
"ToastsPreventTitle": "Prevent Duplicates",
125125
"ToastsPreventIntro": "By setting <code>PreventDuplicates=\"true\"</code> to repeatedly click the button below, only one pop-up window will appear",
126126
"ToastsPreventText": "Prevent Duplicates",
127+
"ToastsAsyncTitle": "Async notification",
128+
"ToastsAsyncIntro": "By setting <code>IsAsync</code>, the pop-up window is displayed, the thread is blocked, and after clicking the close button, the subsequent code continues to execute",
129+
"ToastsAsyncDemoTitle": "Async notification",
130+
"ToastsAsyncDemoStep1Text": "Packing documents, please wait...",
131+
"ToastsAsyncDemoStep2Text": "Packaging completed, downloading...",
132+
"ToastsAsyncDemoStep3Text": "Download completed, close the window automatically",
127133
"ToastsWarning": "Warning notice",
134+
"ToastsAsyncText": "AsyncNotify",
128135
"ToastsCloseTitle": "Toast is closed manually",
129136
"ToastsCloseIntro": "It will not close automatically, you need to manually click the close button. You can customize the event after closing the pop-up window by setting<code>OnCloseAsync</code>callback delegate</code>",
130137
"ToastsCloseNotificationText": "success notification",

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,14 @@
124124
"ToastsPreventTitle": "阻止重复",
125125
"ToastsPreventIntro": "通过设置 <code>PreventDuplicates=\"true\"</code> 重复点击下方按钮时,仅弹窗一次",
126126
"ToastsPreventText": "阻止重复",
127+
"ToastsAsyncTitle": "线程阻塞通知",
128+
"ToastsAsyncIntro": "通过设置 <code>IsAsync</code> 弹窗显示后,线程阻塞,点击关闭按钮后,继续执行后续代码",
129+
"ToastsAsyncDemoTitle": "异步通知",
130+
"ToastsAsyncDemoStep1Text": "正在打包文档,请稍等...",
131+
"ToastsAsyncDemoStep2Text": "打包完成,正在下载...",
132+
"ToastsAsyncDemoStep3Text": "下载完成,自动关窗",
127133
"ToastsWarning": "警告通知",
134+
"ToastsAsyncText": "线程阻塞通知示例",
128135
"ToastsCloseTitle": "Toast 手动关闭",
129136
"ToastsCloseIntro": "不会自动关闭,需要人工点击关闭按钮,可通过设置 <code>OnCloseAsync</code> 回调委托自定义关闭弹窗后事件",
130137
"ToastsCloseNotificationText": "成功通知",

src/BootstrapBlazor/Components/Toast/Toast.razor.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,29 +49,27 @@ public partial class Toast
4949
/// <summary>
5050
/// 获得/设置 弹出框自动关闭时长
5151
/// </summary>
52-
protected string? DelayString => Options.IsAutoHide ? Convert.ToString(Options.Delay) : null;
52+
private string? DelayString => Options.IsAutoHide ? Options.Delay.ToString() : null;
5353

5454
/// <summary>
55-
/// 获得/设置 是否开启动画效果
55+
/// 获得/设置 是否开启动画效果
5656
/// </summary>
57-
protected string? AnimationString => Options.Animation ? null : "false";
57+
private string? AnimationString => Options.Animation ? null : "false";
5858

5959
/// <summary>
6060
/// 获得/设置 ToastOption 实例
6161
/// </summary>
6262
[Parameter]
6363
[NotNull]
64-
#if NET6_0_OR_GREATER
6564
[EditorRequired]
66-
#endif
6765
public ToastOption? Options { get; set; }
6866

6967
/// <summary>
7068
/// 获得/设置 Toast 实例
7169
/// </summary>
7270
/// <value></value>
7371
[CascadingParameter]
74-
protected ToastContainer? ToastContainer { get; set; }
72+
private ToastContainer? ToastContainer { get; set; }
7573

7674
[Inject]
7775
[NotNull]
@@ -100,6 +98,19 @@ protected override void OnParametersSet()
10098
Options.ErrorIcon ??= IconTheme.GetIconByKey(ComponentIcons.ToastErrorIcon);
10199
}
102100

101+
/// <summary>
102+
/// <inheritdoc/>
103+
/// </summary>
104+
protected override async Task OnAfterRenderAsync(bool firstRender)
105+
{
106+
await base.OnAfterRenderAsync(firstRender);
107+
108+
if (!firstRender)
109+
{
110+
await InvokeVoidAsync("update", Id);
111+
}
112+
}
113+
103114
/// <summary>
104115
/// <inheritdoc/>
105116
/// </summary>

src/BootstrapBlazor/Components/Toast/Toast.razor.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function init(id, invoke, callback) {
1212
return toast.toast._config.autohide
1313
}
1414
}
15-
Data.set(id, toast)
15+
Data.set(id, toast);
1616

1717
if (toast.showProgress()) {
1818
toast.progressElement = toast.element.querySelector('.toast-progress')
@@ -31,6 +31,25 @@ export function init(id, invoke, callback) {
3131
toast.toast.show()
3232
}
3333

34+
export function update(id) {
35+
const t = Data.get(id);
36+
const { element, toast } = t;
37+
const autoHide = element.getAttribute('data-bs-autohide') !== 'false';
38+
if(autoHide) {
39+
const delay = parseInt(element.getAttribute('data-bs-delay'));
40+
const progressElement = element.querySelector('.toast-progress');
41+
42+
toast._config.autohide = autoHide;
43+
toast._config.delay = delay;
44+
45+
progressElement.style.width = '100%';
46+
progressElement.style.transition = `width linear ${delay / 1000}s`;
47+
EventHandler.on(progressElement, 'transitionend', e => {
48+
toast.hide();
49+
});
50+
}
51+
}
52+
3453
export function dispose(id) {
3554
const toast = Data.get(id)
3655
Data.remove(id)

src/BootstrapBlazor/Components/Toast/ToastContainer.razor.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ private async Task Show(ToastOption option)
7575
return;
7676
}
7777
}
78-
Toasts.Add(option);
78+
79+
// support update content
80+
if (!Toasts.Contains(option))
81+
{
82+
Toasts.Add(option);
83+
}
7984
await InvokeAsync(StateHasChanged);
8085
}
8186

0 commit comments

Comments
 (0)