Skip to content

Commit 6db9d85

Browse files
authored
feat(DynamicElement): add OnTouchStart/End parameter (#7898)
* refactor: 增加 OnTouchStart/End 参数 * refactor: 使用 TriggerTouchStart/TriggerTouchEnd 方法 * test: 补充单元测试 * Revert "feat(Select): use DynamicElement ensure release event callback (#7894)" This reverts commit c2dcc2e. * revert: 撤销 DisposeAsync 逻辑 * revert: 撤销 OnClick 委托清理逻辑 * refactor: 更新 TriggerTouchStart 写法 * refactor: 格式化代码 * chore: bump version 10.5.1-beta10
1 parent f559e9e commit 6db9d85

8 files changed

Lines changed: 105 additions & 61 deletions

File tree

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.5.1-beta08</Version>
4+
<Version>10.5.1-beta10</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/BaseComponents/DynamicElement.cs

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace BootstrapBlazor.Components;
1212
/// <para lang="zh">动态元素组件</para>
1313
/// <para lang="en">Dynamic element component</para>
1414
/// </summary>
15-
public class DynamicElement : BootstrapComponentBase, IAsyncDisposable
15+
public class DynamicElement : BootstrapComponentBase
1616
{
1717
/// <summary>
1818
/// <para lang="zh">获得/设置 TagName 属性 默认为 div</para>
@@ -78,6 +78,34 @@ public class DynamicElement : BootstrapComponentBase, IAsyncDisposable
7878
[Parameter]
7979
public bool TriggerContextMenu { get; set; }
8080

81+
/// <summary>
82+
/// <para lang="zh">获得/设置 OnTouchStart 回调委托</para>
83+
/// <para lang="en">Gets or sets the OnTouchStart callback delegate</para>
84+
/// </summary>
85+
[Parameter]
86+
public Func<TouchEventArgs, Task>? OnTouchStart { get; set; }
87+
88+
/// <summary>
89+
/// <para lang="zh">获得/设置 OnTouchEnd 回调委托</para>
90+
/// <para lang="en">Gets or sets the OnTouchEnd callback delegate</para>
91+
/// </summary>
92+
[Parameter]
93+
public Func<TouchEventArgs, Task>? OnTouchEnd { get; set; }
94+
95+
/// <summary>
96+
/// <para lang="zh">获得/设置 是否触发 OnTouchStart 事件 默认 false</para>
97+
/// <para lang="en">Gets or sets whether to trigger OnTouchStart events. Default is false</para>
98+
/// </summary>
99+
[Parameter]
100+
public bool TriggerTouchStart { get; set; }
101+
102+
/// <summary>
103+
/// <para lang="zh">获得/设置 是否触发 OnTouchEnd 事件 默认 false</para>
104+
/// <para lang="en">Gets or sets whether to trigger OnTouchEnd events. Default is false</para>
105+
/// </summary>
106+
[Parameter]
107+
public bool TriggerTouchEnd { get; set; }
108+
81109
/// <summary>
82110
/// <para lang="zh">获得/设置 内容组件</para>
83111
/// <para lang="en">Gets or sets the child content</para>
@@ -139,6 +167,16 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
139167
builder.AddEventPreventDefaultAttribute(9, "oncontextmenu", true);
140168
}
141169

170+
if (IsTriggerTouchStart())
171+
{
172+
builder.AddAttribute(11, "ontouchstart", EventCallback.Factory.Create<TouchEventArgs>(this, OnTriggerTouchStart));
173+
}
174+
175+
if (IsTriggerTouchEnd())
176+
{
177+
builder.AddAttribute(12, "ontouchend", EventCallback.Factory.Create<TouchEventArgs>(this, OnTriggerTouchEnd));
178+
}
179+
142180
builder.AddContent(10, ChildContent);
143181

144182
if (GenerateElement || IsTriggerClick() || IsTriggerDoubleClick())
@@ -153,6 +191,10 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
153191

154192
private bool IsTriggerContextMenu() => TriggerContextMenu && OnContextMenu != null;
155193

194+
private bool IsTriggerTouchStart() => TriggerTouchStart && OnTouchStart != null;
195+
196+
private bool IsTriggerTouchEnd() => TriggerTouchEnd && OnTouchEnd != null;
197+
156198
private async Task OnTriggerClick()
157199
{
158200
if (OnClick != null)
@@ -177,28 +219,19 @@ private async Task OnTriggerContextMenu(MouseEventArgs e)
177219
}
178220
}
179221

180-
/// <summary>
181-
/// <para lang="zh">异步释放资源</para>
182-
/// <para lang="en">Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously</para>
183-
/// </summary>
184-
/// <param name="disposing"></param>
185-
protected virtual async ValueTask DisposeAsync(bool disposing)
222+
private async Task OnTriggerTouchStart(TouchEventArgs e)
186223
{
187-
if (disposing)
224+
if (OnTouchStart != null)
188225
{
189-
OnClick = null;
190-
OnDoubleClick = null;
191-
OnContextMenu = null;
192-
ChildContent = null;
226+
await OnTouchStart(e);
193227
}
194228
}
195229

196-
/// <summary>
197-
/// <inheritdoc/>
198-
/// </summary>
199-
public async ValueTask DisposeAsync()
230+
private async Task OnTriggerTouchEnd(TouchEventArgs e)
200231
{
201-
await DisposeAsync(true);
202-
GC.SuppressFinalize(this);
232+
if (OnTouchEnd != null)
233+
{
234+
await OnTouchEnd(e);
235+
}
203236
}
204237
}

src/BootstrapBlazor/Components/Button/ButtonBase.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,16 +334,6 @@ protected override async ValueTask DisposeAsync(bool disposing)
334334
{
335335
if (disposing)
336336
{
337-
if (OnClick.HasDelegate)
338-
{
339-
OnClick = EventCallback<MouseEventArgs>.Empty;
340-
}
341-
342-
if (OnClickWithoutRender != null)
343-
{
344-
OnClickWithoutRender = null;
345-
}
346-
347337
if (IsAsync && ValidateForm != null)
348338
{
349339
ValidateForm.UnregisterAsyncSubmitButton(this);

src/BootstrapBlazor/Components/Select/Select.razor

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@namespace BootstrapBlazor.Components
1+
@namespace BootstrapBlazor.Components
22
@using Microsoft.AspNetCore.Components.Web.Virtualization
33
@typeparam TValue
44
@inherits SimpleSelectBase<TValue>
@@ -22,8 +22,7 @@
2222
}
2323
else
2424
{
25-
<input type="text" id="@InputId" disabled="@Disabled" placeholder="@PlaceHolder" class="@InputClassString"
26-
value="@SelectedRow?.Text" @onchange="@_onChangeEventCallback" readonly="@ReadonlyString" />
25+
<input type="text" id="@InputId" disabled="@Disabled" placeholder="@PlaceHolder" class="@InputClassString" value="@SelectedRow?.Text" @onchange="OnChange" readonly="@ReadonlyString" />
2726
}
2827
<span class="@AppendClassString"><i class="@DropdownIcon"></i></span>
2928
</div>
@@ -93,7 +92,7 @@
9392

9493
@code {
9594
RenderFragment<SelectedItem> RenderRow => item =>
96-
@<DynamicElement class="@ActiveItem(item)" OnClick="() => OnClickItem(item)">
95+
@<div class="@ActiveItem(item)" @onclick="() => OnClickItem(item)">
9796
@if (ItemTemplate != null)
9897
{
9998
@ItemTemplate(item)
@@ -106,7 +105,7 @@
106105
{
107106
@item.Text
108107
}
109-
</DynamicElement>;
108+
</div>;
110109

111110
RenderFragment<PlaceholderContext> RenderPlaceHolderRow => context =>
112111
@<div class="dropdown-item">

src/BootstrapBlazor/Components/Select/Select.razor.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,6 @@ public bool IsUseActiveWhenValueIsNull
202202

203203
private string _defaultVirtualizedItemText = "";
204204

205-
private EventCallback<ChangeEventArgs> _onChangeEventCallback = EventCallback<ChangeEventArgs>.Empty;
206-
207205
private SelectedItem? SelectedItem { get; set; }
208206

209207
private SelectedItem? SelectedRow
@@ -236,10 +234,6 @@ protected override void OnParametersSet()
236234
NoSearchDataText ??= Localizer[nameof(NoSearchDataText)];
237235
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
238236
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
239-
240-
_onChangeEventCallback = IsEditable
241-
? EventCallback.Factory.Create<ChangeEventArgs>(this, OnChange)
242-
: EventCallback<ChangeEventArgs>.Empty;
243237
}
244238

245239
/// <summary>
@@ -395,8 +389,6 @@ private async Task OnClickItem(SelectedItem item)
395389
_defaultVirtualizedItemText = item.Text;
396390
await SelectedItemChanged(item);
397391
}
398-
399-
StateHasChanged();
400392
}
401393

402394
private async Task SelectedItemChanged(SelectedItem item)
@@ -509,19 +501,4 @@ private async Task OnChange(ChangeEventArgs args)
509501
?? allItems.Find(i => !i.IsDisabled);
510502
return item;
511503
}
512-
513-
/// <summary>
514-
/// <inheritdoc/>
515-
/// </summary>
516-
/// <param name="disposing"></param>
517-
/// <returns></returns>
518-
protected override ValueTask DisposeAsync(bool disposing)
519-
{
520-
if (disposing)
521-
{
522-
_onChangeEventCallback = EventCallback<ChangeEventArgs>.Empty;
523-
}
524-
525-
return base.DisposeAsync(disposing);
526-
}
527504
}

src/BootstrapBlazor/Components/Table/Table.razor

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@
270270
class="@GetRowClassString(item, "table-row")" style="@GetRowStyleString(item)"
271271
TriggerContextMenu="ContextMenuZone != null"
272272
OnContextMenu="e => OnContextMenu(e, item)"
273-
@ontouchstart="e => OnTouchStart(e, item)"
274-
@ontouchend="OnTouchEnd"
273+
TriggerTouchStart="true" OnTouchStart="e => OnTouchStart(e, item)"
274+
TriggerTouchEnd="true" OnTouchEnd="OnTouchEnd"
275275
TriggerClick="@(ClickToSelect || OnClickRowCallback != null)"
276276
OnClick="() => ClickRow(item)">
277277
@if (IsMultipleSelect)
@@ -734,7 +734,8 @@
734734
@<DynamicElement @key="GetKeyByITem(item)" TagName="tr"
735735
class="@GetRowClassString(item)" style="@GetRowStyleString(item)"
736736
TriggerContextMenu="ContextMenuZone != null" OnContextMenu="e => OnContextMenu(e, item)"
737-
@ontouchstart="e => OnTouchStart(e, item)" @ontouchend="OnTouchEnd"
737+
TriggerTouchStart="true" OnTouchStart="e => OnTouchStart(e, item)"
738+
TriggerTouchEnd="true" OnTouchEnd="OnTouchEnd"
738739
TriggerClick="@(ClickToSelect || OnClickRowCallback != null)" OnClick="() => ClickRow(item)"
739740
TriggerDoubleClick="@(DoubleClickToEdit || OnDoubleClickRowCallback != null)"
740741
OnDoubleClick="() => DoubleClickRow(item)">

src/BootstrapBlazor/Components/Table/Table.razor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2000,9 +2000,10 @@ private async Task OnTouchStart(TouchEventArgs e, TItem item)
20002000
}
20012001
}
20022002

2003-
private void OnTouchEnd()
2003+
private Task OnTouchEnd(TouchEventArgs e)
20042004
{
20052005
TouchStart = false;
2006+
return Task.CompletedTask;
20062007
}
20072008

20082009
private object? GetKeyByITem(TItem item) => SortableList != null ? item : null; //OnGetRowKey?.Invoke(item);

test/UnitTest/Components/DynamicElementTest.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
55

6+
using Microsoft.AspNetCore.Components.Web;
7+
68
namespace UnitTest.Components;
79

810
public class DynamicElementTest
@@ -18,4 +20,45 @@ public void Key_OK()
1820

1921
Assert.Equal("<div></div>", cut.Markup);
2022
}
23+
24+
[Fact]
25+
public void TouchEvents_Ok()
26+
{
27+
var context = new BunitContext();
28+
TouchEventArgs? touchStartArgs = null;
29+
TouchEventArgs? touchEndArgs = null;
30+
var touchStartEventArgs = new TouchEventArgs
31+
{
32+
Touches = [new TouchPoint { ClientX = 10, ClientY = 20, ScreenX = 30, ScreenY = 40 }]
33+
};
34+
var touchEndEventArgs = new TouchEventArgs
35+
{
36+
ChangedTouches = [new TouchPoint { ClientX = 11, ClientY = 21, ScreenX = 31, ScreenY = 41 }]
37+
};
38+
39+
var cut = context.Render<DynamicElement>(pb =>
40+
{
41+
pb.Add(a => a.TagName, "span");
42+
pb.Add(a => a.TriggerTouchStart, true);
43+
pb.Add(a => a.OnTouchStart, e =>
44+
{
45+
touchStartArgs = e;
46+
return Task.CompletedTask;
47+
});
48+
pb.Add(a => a.TriggerTouchEnd, true);
49+
pb.Add(a => a.OnTouchEnd, e =>
50+
{
51+
touchEndArgs = e;
52+
return Task.CompletedTask;
53+
});
54+
pb.AddChildContent("Touch");
55+
});
56+
57+
var element = cut.Find("span");
58+
element.TriggerEvent("ontouchstart", touchStartEventArgs);
59+
element.TriggerEvent("ontouchend", touchEndEventArgs);
60+
61+
Assert.Same(touchStartEventArgs, touchStartArgs);
62+
Assert.Same(touchEndEventArgs, touchEndArgs);
63+
}
2164
}

0 commit comments

Comments
 (0)