Skip to content

Commit 8b8ef2c

Browse files
authored
perf(Message): improve performance (#7094)
* doc: 更新示例 * chore: 更新字典 * refactor: 精简代码 * refactor: 移除 Clear 方法参数传递 * chore: 增加字典 * feat: 支持全局配置自动隐藏时长设置 * doc: 更新注释 * feat: 精简反转逻辑 * refactor: 更新 Clear 方法 * chore: 增加命名空间 * refactor: 更新 init 接口参数 * refactor: 重构 Dismiss 逻辑提高性能 * fix: 修复异步消息未清除 dom 问题 * refactor: 更新关闭逻辑 * refactor: 移除 click 事件委托 * refactor: 精简代码 * test: 更新单元测试 * refactor: 精简代码 * perf: 提高性能
1 parent e7d93b0 commit 8b8ef2c

File tree

7 files changed

+121
-89
lines changed

7 files changed

+121
-89
lines changed

exclusion.dic

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,5 @@ dotx
121121
Modbus
122122
Protocol
123123
vditor
124+
alertdialog
125+
blazorbootstrap

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@page "/message"
1+
@page "/message"
22
@inject IStringLocalizer<Messages> Localizer
33
@inject MessageService MessageService
44

@@ -20,8 +20,18 @@ private MessageService? MessageService { get; set; }
2020
});</Pre>
2121

2222
<DemoBlock Title="@Localizer["MessagesNormalTitle"]" Introduction="@Localizer["MessagesNormalIntro"]" Name="Normal">
23-
<button class="btn btn-primary" @onclick="@ShowMessage">@Localizer["MessagesMessagePrompt"]</button>
24-
<Message @ref="Message" Placement="Placement.Bottom" />
23+
<section ignore class="row form-inline g-3">
24+
<div class="col-12">
25+
<BootstrapInputGroup>
26+
<BootstrapInputGroupLabel DisplayText="Placement"></BootstrapInputGroupLabel>
27+
<RadioList @bind-Value="@_placement" Items="@_items"></RadioList>
28+
</BootstrapInputGroup>
29+
</div>
30+
<div class="col-12">
31+
<button class="btn btn-primary" @onclick="@ShowMessage">@Localizer["MessagesMessagePrompt"]</button>
32+
</div>
33+
</section>
34+
<Message @ref="Message" Placement="@Placement"></Message>
2535
</DemoBlock>
2636

2737
<DemoBlock Title="@Localizer["MessagesAsyncTitle"]" Introduction="@Localizer["MessagesAsyncIntro"]" Name="Async">
@@ -70,7 +80,6 @@ private MessageService? MessageService { get; set; }
7080

7181
<DemoBlock Title="@Localizer["MessagesTemplateTitle"]" Introduction="@Localizer["MessagesTemplateIntro"]" Name="Template">
7282
<button class="btn btn-primary" @onclick="@ShowTemplateMessage">@Localizer["MessagesTemplatePrompt"]</button>
73-
<Message @ref="Message1" Placement="Placement.Bottom" />
7483
</DemoBlock>
7584

7685
<DemoBlock Title="@Localizer["MessagesShowModeTitle"]" Introduction="@Localizer["MessagesShowModeIntro"]" Name="ShowMode">

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
@@ -18,13 +18,20 @@ public sealed partial class Messages
1818

1919
private readonly MessageOption _option = new();
2020

21+
private long _count = 0;
22+
23+
private string _placement = "Top";
24+
25+
private readonly List<SelectedItem> _items = [new SelectedItem("Top", "Top"), new SelectedItem("Bottom", "Bottom")];
26+
27+
private Placement Placement => _placement == "Top" ? Placement.Top : Placement.Bottom;
28+
2129
private async Task ShowMessage()
2230
{
23-
Message.SetPlacement(Placement.Top);
2431
await MessageService.Show(new MessageOption()
2532
{
26-
Content = "This is a reminder message"
27-
});
33+
Content = $"This is a reminder message {_count++}"
34+
}, Message);
2835
}
2936

3037
private async Task ShowAsyncMessage()
@@ -97,7 +104,7 @@ private async Task ShowBottomMessage()
97104
{
98105
await MessageService.Show(new MessageOption()
99106
{
100-
Content = $"This is a reminder message - {DateTime.Now:mm:ss}",
107+
Content = $"This is a reminder message - {_count++}",
101108
Icon = "fa-solid fa-circle-info",
102109
}, Message1);
103110
}
@@ -111,13 +118,11 @@ await MessageService.Show(new MessageOption()
111118
});
112119
}
113120

114-
private int lastCount = 0;
115-
116121
private Task ShowLastOnlyMessage() => MessageService.Show(new MessageOption()
117122
{
118123
ShowShadow = true,
119124
ShowMode = MessageShowMode.Single,
120-
Content = lastCount++.ToString()
125+
Content = $"This is a reminder message - {_count++}"
121126
});
122127

123128
private static AttributeItem[] GetAttributes() =>
Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,29 @@
1-
@namespace BootstrapBlazor.Components
1+
@namespace BootstrapBlazor.Components
22
@inherits BootstrapModuleComponentBase
33
@attribute [BootstrapModuleAutoLoader(JSObjectReference = true)]
44

55
<div id="@Id" class="@ClassString" style="@StyleName" role="alert">
6-
@if (Placement == Placement.Top)
6+
@foreach (var item in MessagesForRender)
77
{
8-
foreach (var item in _messages)
9-
{
10-
<div @key="item" id="@GetItemId(item)" role="alertdialog" class="@GetItemClassString(item)" data-bb-autohide="@GetAutoHideString(item)" data-bb-delay="@item.Delay">
11-
@if (!string.IsNullOrEmpty(item.Icon))
8+
<div @key="item" id="@GetItemId(item)" role="alertdialog" class="@GetItemClassString(item)" data-bb-autohide="@GetAutoHideString(item)" data-bb-delay="@item.Delay">
9+
@if (!string.IsNullOrEmpty(item.Icon))
10+
{
11+
<i class="@item.Icon"></i>
12+
}
13+
<div>
14+
@if (item.ChildContent != null)
1215
{
13-
<i class="@item.Icon"></i>
16+
@item.ChildContent
1417
}
15-
<div>
16-
@if (item.ChildContent != null)
17-
{
18-
@item.ChildContent
19-
}
20-
else
21-
{
22-
@item.Content
23-
}
24-
</div>
25-
@if (item.ShowDismiss)
18+
else
2619
{
27-
<button type="button" class="btn-close" aria-label="close"></button>
20+
@item.Content
2821
}
2922
</div>
30-
}
31-
}
32-
else
33-
{
34-
for (var index = _messages.Count; index > 0; index--)
35-
{
36-
var item = _messages[index - 1];
37-
<div @key="item" id="@GetItemId(item)" role="alertdialog" class="@GetItemClassString(item)" data-bb-autohide="@GetAutoHideString(item)" data-bb-delay="@item.Delay">
38-
@if (!string.IsNullOrEmpty(item.Icon))
39-
{
40-
<i class="@item.Icon"></i>
41-
}
42-
<div>
43-
@if (item.ChildContent != null)
44-
{
45-
@item.ChildContent
46-
}
47-
else
48-
{
49-
@item.Content
50-
}
51-
</div>
52-
@if (item.ShowDismiss)
53-
{
54-
<button type="button" class="btn-close" aria-label="close"></button>
55-
}
56-
</div>
57-
}
23+
@if (item.ShowDismiss)
24+
{
25+
<button type="button" class="btn-close" aria-label="close"></button>
26+
}
27+
</div>
5828
}
5929
</div>

src/BootstrapBlazor/Components/Message/Message.razor.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
@@ -27,6 +27,10 @@ public partial class Message
2727

2828
private readonly List<MessageOption> _messages = [];
2929

30+
private IEnumerable<MessageOption> MessagesForRender => Placement == Placement.Bottom
31+
? _messages.AsEnumerable().Reverse()
32+
: _messages;
33+
3034
/// <summary>
3135
/// 获得/设置 显示位置 默认为 Top
3236
/// </summary>
@@ -55,7 +59,7 @@ protected override void OnInitialized()
5559
/// <inheritdoc/>
5660
/// </summary>
5761
/// <returns></returns>
58-
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, nameof(Clear));
62+
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop);
5963

6064
private static string? GetAutoHideString(MessageOption option) => option.IsAutoHide ? "true" : null;
6165

@@ -86,7 +90,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
8690
}
8791

8892
/// <summary>
89-
/// 设置 Toast 容器位置方法
93+
/// 设置 容器位置方法
9094
/// </summary>
9195
/// <param name="placement"></param>
9296
public void SetPlacement(Placement placement)
@@ -105,33 +109,39 @@ private async Task Show(MessageOption option)
105109
if (!_messages.Contains(option))
106110
{
107111
_messages.Add(option);
108-
_msgId = GetItemId(option);
109112
}
113+
_msgId = GetItemId(option);
110114
await InvokeAsync(StateHasChanged);
111115
}
112116

113117
/// <summary>
114118
/// 清除 Message 方法 由 JSInvoke 触发
115119
/// </summary>
116120
[JSInvokable]
117-
public Task Clear()
121+
public void Clear(string id)
118122
{
119-
_messages.Clear();
123+
var option = _messages.Find(i => GetItemId(i) == id);
124+
if (option != null)
125+
{
126+
_messages.Remove(option);
127+
}
128+
120129
StateHasChanged();
121-
return Task.CompletedTask;
122130
}
123131

124132
/// <summary>
125133
/// OnDismiss 回调方法 由 JSInvoke 触发
126134
/// </summary>
127135
/// <param name="id"></param>
128136
[JSInvokable]
129-
public async Task Dismiss(string id)
137+
public async ValueTask Dismiss(string id)
130138
{
131139
var option = _messages.Find(i => GetItemId(i) == id);
132140
if (option is { OnDismiss: not null })
133141
{
134142
await option.OnDismiss();
143+
_messages.Remove(option);
144+
StateHasChanged();
135145
}
136146
}
137147

src/BootstrapBlazor/Components/Message/Message.razor.js

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
import Data from "../../modules/data.js"
1+
import Data from "../../modules/data.js"
22
import EventHandler from "../../modules/event-handler.js"
33

4-
export function init(id, invoke, callback) {
4+
export function init(id, invoke) {
55
const el = document.getElementById(id)
6-
const msg = { el, invoke, callback, items: [] }
6+
const msg = { el, invoke, items: [] }
77
Data.set(id, msg)
88
}
99

1010
export function show(id, msgId) {
11-
const msg = Data.get(id)
1211
const el = document.getElementById(msgId)
1312
if (el === null) {
1413
return
1514
}
1615

16+
const msg = Data.get(id)
1717
let msgItem = msg.items.find(i => i.el.id === msgId)
1818
if (msgItem === void 0) {
1919
msgItem = { el, animationId: null }
2020
msg.items.push(msgItem)
2121
}
2222

2323
if (msgItem.animationId) {
24-
cancelAnimationFrame(msgItem.animationId);
24+
return;
2525
}
2626

2727
const autoHide = el.getAttribute('data-bb-autohide') === 'true';
@@ -46,28 +46,25 @@ export function show(id, msgId) {
4646
el.classList.add('show');
4747

4848
const close = () => {
49-
EventHandler.off(el, 'click')
50-
el.classList.remove('show');
51-
const hideHandler = setTimeout(function () {
52-
clearTimeout(hideHandler);
49+
el.classList.add("d-none");
5350

54-
msg.items.pop();
55-
if (msg.items.length === 0) {
56-
msg.invoke.invokeMethodAsync(msg.callback);
57-
}
58-
}, 500);
51+
msg.items = msg.items.filter(i => i.el.id !== msgId);
52+
msg.invoke.invokeMethodAsync("Clear", msgId);
5953
};
6054

61-
EventHandler.on(el, 'click', '.btn-close', e => {
55+
EventHandler.on(el, 'click', '.btn-close', async e => {
6256
e.preventDefault();
6357
e.stopPropagation();
6458

6559
const alert = e.delegateTarget.closest('.alert');
6660
if (alert) {
61+
EventHandler.off(el, 'click')
62+
alert.classList.add("d-none");
63+
6764
const alertId = alert.getAttribute('id');
68-
msg.invoke.invokeMethodAsync('Dismiss', alertId);
65+
msg.items = msg.items.filter(i => i.el.id !== alertId);
66+
await msg.invoke.invokeMethodAsync('Dismiss', alertId);
6967
}
70-
close();
7168
});
7269
}
7370

0 commit comments

Comments
 (0)