Skip to content

Commit be5a5b8

Browse files
authored
refactor(Checkbox): redesign javascript invoke improve performance (#4629)
* refactor: 移除关键字 * test: 更新单元测试 * refactor: 重构 OnTriggerClickAsync # Conflicts: # src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.cs # src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.js * test: 更新单元测试 * refactor: 重构客户端交互逻辑提供性能 * test: 更新单元测试 * refactor: 更新关键字 * doc: 增加注释
1 parent 5d1e209 commit be5a5b8

File tree

5 files changed

+60
-75
lines changed

5 files changed

+60
-75
lines changed

src/BootstrapBlazor/Components/Checkbox/Checkbox.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ else
2020
@code {
2121
RenderFragment RenderCheckbox =>
2222
@<div @attributes="AdditionalAttributes" class="@ClassString">
23-
<input class="@InputClassString" type="checkbox" id="@Id" disabled="@Disabled" checked="@CheckedString" data-bb-trigger-before="@TriggerBeforeValueString" data-bb-stop-propagation="@StopPropagationString" />
23+
<input class="@InputClassString" type="checkbox" id="@Id" disabled="@Disabled" checked="@CheckedString" data-bb-stop-propagation="@StopPropagationString" />
2424
@if (IsShowAfterLabel)
2525
{
2626
@RenderLabel

src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.cs

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ public partial class Checkbox<TValue> : ValidateBase<TValue>
102102

103103
private string? StopPropagationString => StopPropagation ? "true" : null;
104104

105-
private string? TriggerBeforeValueString => OnBeforeStateChanged == null ? null : "true";
106-
107105
/// <summary>
108106
/// <inheritdoc/>
109107
/// </summary>
@@ -159,55 +157,49 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
159157
/// <inheritdoc/>
160158
/// </summary>
161159
/// <returns></returns>
162-
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new
163-
{
164-
TriggerOnBeforeStateChanged = nameof(TriggerOnBeforeStateChanged),
165-
TriggerClick = nameof(TriggerClick),
166-
SyncStateCallback = nameof(SyncStateCallback)
167-
});
160+
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, nameof(OnTriggerClickAsync));
168161

169-
private CheckboxState NextState => State == CheckboxState.Checked ? CheckboxState.UnChecked : CheckboxState.Checked;
162+
/// <summary>
163+
/// 触发 Click 方法
164+
/// </summary>
165+
/// <returns></returns>
166+
public async Task TriggerClick() => await OnTriggerClickAsync();
170167

171168
/// <summary>
172-
/// 触发 OnBeforeStateChanged 回调方法 由 JavaScript 调用
169+
/// 触发 Click 方法 由 JavaScript 调用
173170
/// </summary>
171+
/// <returns></returns>
174172
[JSInvokable]
175-
public async ValueTask TriggerOnBeforeStateChanged()
173+
public async ValueTask<bool> OnTriggerClickAsync(CheckboxState? state = null)
176174
{
175+
// 本组件由于支持 OnBeforeStateChanged 回调方法,所以设计上移除了 onclick 事件,改为通过 JS 调用 TriggerClick 方法
176+
// state 有值时表示同步状态功能
177+
if (state.HasValue)
178+
{
179+
State = state.Value;
180+
return true;
181+
}
182+
183+
// 调用 OnBeforeStateChanged 回调方法查看是否阻止状态改变
184+
// 返回 true 时改变状态,返回 false 时不改变状态阻止状态改变 preventDefault
185+
var val = State == CheckboxState.Checked ? CheckboxState.UnChecked : CheckboxState.Checked;
177186
if (OnBeforeStateChanged != null)
178187
{
179-
var ret = await OnBeforeStateChanged(NextState);
180-
if (ret)
188+
var ret = await OnBeforeStateChanged(val);
189+
if (ret == false)
181190
{
182-
await TriggerClick();
191+
// 阻止状态改变
192+
return false;
183193
}
184194
}
185-
}
186195

187-
/// <summary>
188-
/// 同步 <see cref="State"/> 值方法 由 JavaScript 调用
189-
/// </summary>
190-
/// <param name="state"></param>
191-
/// <returns></returns>
192-
[JSInvokable]
193-
public ValueTask SyncStateCallback(CheckboxState state)
194-
{
195-
State = state;
196-
return ValueTask.CompletedTask;
197-
}
198-
199-
/// <summary>
200-
/// 触发 Click 方法 由 JavaScript 调用
201-
/// </summary>
202-
/// <returns></returns>
203-
[JSInvokable]
204-
public async ValueTask TriggerClick()
205-
{
206-
var render = await InternalStateChanged(NextState);
196+
// 改变状态 由点击事件触发
197+
var render = await InternalStateChanged(val);
207198
if (render)
208199
{
209200
StateHasChanged();
210201
}
202+
return true;
211203
}
212204

213205
/// <summary>
@@ -246,7 +238,7 @@ private async Task<bool> InternalStateChanged(CheckboxState state)
246238
/// 设置 复选框状态方法
247239
/// </summary>
248240
/// <param name="state"></param>
249-
public virtual async Task SetState(CheckboxState state)
241+
public async Task SetState(CheckboxState state)
250242
{
251243
if (!_paddingStateChanged)
252244
{

src/BootstrapBlazor/Components/Checkbox/Checkbox.razor.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { setIndeterminate } from "../../modules/utility.js"
22
import EventHandler from "../../modules/event-handler.js"
33

4-
export function init(id, invoke, options) {
4+
export function init(id, invoke, method) {
55
const el = document.getElementById(id);
66
if (el === null) {
77
return;
@@ -14,31 +14,20 @@ export function init(id, invoke, options) {
1414
}
1515

1616
const state = el.getAttribute("data-bb-state");
17-
const trigger = el.getAttribute("data-bb-trigger-before");
18-
1917
if (state) {
2018
el.removeAttribute('data-bb-state');
21-
await invoke.invokeMethodAsync(options.syncStateCallback, parseInt(state));
2219

2320
if (state === "1") {
2421
el.parentElement.classList.remove('is-checked');
2522
}
2623
else {
2724
el.parentElement.classList.add('is-checked');
2825
}
29-
30-
if (trigger !== "true") {
31-
return;
32-
}
3326
}
34-
35-
if (trigger === 'true') {
27+
const result = await invoke.invokeMethodAsync(method, state == "1" ? 0 : 1);
28+
if (result === false) {
3629
e.preventDefault();
37-
await invoke.invokeMethodAsync(options.triggerOnBeforeStateChanged);
38-
return;
3930
}
40-
41-
await invoke.invokeMethodAsync(options.triggerClick);
4231
});
4332
}
4433

test/UnitTest/Components/CheckboxListTest.cs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ public void StopPropagation_Ok()
3737
Assert.Contains("data-bb-stop-propagation=\"true\"", cut.Markup);
3838
}
3939

40-
[Fact]
41-
public async Task SyncStateCallback_Ok()
42-
{
43-
var cut = Context.RenderComponent<Checkbox<bool>>(builder =>
44-
{
45-
builder.Add(a => a.State, CheckboxState.UnChecked);
46-
});
47-
Assert.Equal(CheckboxState.UnChecked, cut.Instance.State);
48-
49-
await cut.InvokeAsync(() => cut.Instance.SyncStateCallback(CheckboxState.Checked));
50-
Assert.Equal(CheckboxState.Checked, cut.Instance.State);
51-
}
52-
5340
[Fact]
5441
public void ShowAfterLabel_Ok()
5542
{
@@ -82,14 +69,31 @@ public async Task Checkbox_OnBeforeStateChanged()
8269
});
8370
Assert.False(cut.Instance.Value);
8471

85-
await cut.InvokeAsync(cut.Instance.TriggerOnBeforeStateChanged);
72+
await cut.InvokeAsync(cut.Instance.TriggerClick);
8673
Assert.True(cut.Instance.Value);
8774

8875
confirm = false;
89-
await cut.InvokeAsync(cut.Instance.TriggerOnBeforeStateChanged);
76+
await cut.InvokeAsync(cut.Instance.TriggerClick);
9077
Assert.True(cut.Instance.Value);
9178
}
9279

80+
[Fact]
81+
public async Task Checkbox_OnTriggerClickAsync()
82+
{
83+
var cut = Context.RenderComponent<Checkbox<bool>>();
84+
Assert.False(cut.Instance.Value);
85+
86+
// JavaScript 调用 OnTriggerClickAsync 方法
87+
var val = await cut.Instance.OnTriggerClickAsync(CheckboxState.UnChecked);
88+
89+
Assert.True(val);
90+
Assert.Equal(CheckboxState.UnChecked, cut.Instance.State);
91+
92+
val = await cut.Instance.OnTriggerClickAsync(CheckboxState.Checked);
93+
Assert.True(val);
94+
Assert.Equal(CheckboxState.Checked, cut.Instance.State);
95+
}
96+
9397
[Fact]
9498
public void Checkbox_Dispose()
9599
{
@@ -104,7 +108,7 @@ public void Checkbox_Dispose()
104108

105109
var methodInfo = checkbox.GetType().GetMethod("DisposeAsync", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
106110
Assert.NotNull(methodInfo);
107-
methodInfo.Invoke(checkbox, new object[] { false });
111+
methodInfo.Invoke(checkbox, [false]);
108112
}
109113

110114
[Fact]
@@ -410,20 +414,20 @@ public async Task OnMaxSelectedCountExceed_Ok()
410414

411415
await cut.InvokeAsync(async () =>
412416
{
413-
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
417+
await checkboxes[0].Instance.TriggerClick();
414418
});
415419
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
416420

417421
await cut.InvokeAsync(async () =>
418422
{
419-
await checkboxes[1].Instance.TriggerOnBeforeStateChanged();
423+
await checkboxes[1].Instance.TriggerClick();
420424
});
421425
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
422426

423427
// 选中第三个由于限制无法选中
424428
await cut.InvokeAsync(async () =>
425429
{
426-
await checkboxes[2].Instance.TriggerOnBeforeStateChanged();
430+
await checkboxes[2].Instance.TriggerClick();
427431
});
428432
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
429433
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
@@ -434,7 +438,7 @@ await cut.InvokeAsync(async () =>
434438
max = false;
435439
await cut.InvokeAsync(async () =>
436440
{
437-
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
441+
await checkboxes[0].Instance.TriggerClick();
438442
});
439443
Assert.Equal(CheckboxState.UnChecked, checkboxes[0].Instance.State);
440444
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);

test/UnitTest/Components/TreeViewTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,20 +235,20 @@ public async Task OnMaxSelectedCountExceed_Ok()
235235

236236
await cut.InvokeAsync(async () =>
237237
{
238-
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
238+
await checkboxes[0].Instance.TriggerClick();
239239
});
240240
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
241241

242242
await cut.InvokeAsync(async () =>
243243
{
244-
await checkboxes[1].Instance.TriggerOnBeforeStateChanged();
244+
await checkboxes[1].Instance.TriggerClick();
245245
});
246246
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
247247

248248
// 选中第三个由于限制无法选中
249249
await cut.InvokeAsync(async () =>
250250
{
251-
await checkboxes[2].Instance.TriggerOnBeforeStateChanged();
251+
await checkboxes[2].Instance.TriggerClick();
252252
});
253253
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
254254
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
@@ -259,7 +259,7 @@ await cut.InvokeAsync(async () =>
259259
max = false;
260260
await cut.InvokeAsync(async () =>
261261
{
262-
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
262+
await checkboxes[0].Instance.TriggerClick();
263263
});
264264
Assert.Equal(CheckboxState.UnChecked, checkboxes[0].Instance.State);
265265
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);

0 commit comments

Comments
 (0)