ASP.NET Core Blazor 事件处理ASP.NET Core Blazor event handling

本文内容

作者:Luke LathamDaniel Roth

Razor 组件提供事件处理功能。对于具有委托类型值且名为 @on{EVENT}(例如 @onclick)的 HTML 元素特性,Razor 组件将该特性的值视为事件处理程序。

在 UI 中选择该按钮时,以下代码调用 UpdateHeading 方法:

  1. <button class="btn btn-primary" @onclick="UpdateHeading">
  2. Update heading
  3. </button>
  4. @code {
  5. private void UpdateHeading(MouseEventArgs e)
  6. {
  7. ...
  8. }
  9. }

UI 中的该复选框更改时,以下代码调用 CheckChanged 方法:

  1. <input type="checkbox" class="form-check-input" @onchange="CheckChanged" />
  2. @code {
  3. private void CheckChanged()
  4. {
  5. ...
  6. }
  7. }

事件处理程序也可以是异步处理程序,并返回 Task无需手动调用 StateHasChanged异常发生时,它们将被记录下来。

在下面的示例中,选择该按钮时,异步调用 UpdateHeading

  1. <button class="btn btn-primary" @onclick="UpdateHeading">
  2. Update heading
  3. </button>
  4. @code {
  5. private async Task UpdateHeading(MouseEventArgs e)
  6. {
  7. ...
  8. }
  9. }

事件参数类型Event argument types

对于某些事件,允许使用事件参数类型。仅当方法中使用了事件类型时,才需要在方法调用中指定该事件类型。

支持的 EventArgs 显示在下表中。

事件DOM 事件和说明
剪贴板ClipboardEventArgsoncut, oncopy, onpaste
拖动DragEventArgsondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragendDataTransferDataTransferItem 保留拖动的项数据。
错误ErrorEventArgsonerror
事件EventArgs常规onactivateonbeforeactivateonbeforedeactivateondeactivateonendedonfullscreenchangeonfullscreenerroronloadeddataonloadedmetadataonpointerlockchangeonpointerlockerroronreadystatechangeonscroll剪贴板onbeforecut, onbeforecopy, onbeforepaste输入oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit介质oncanplayoncanplaythroughoncuechangeondurationchangeonemptiedonpauseonplayonplayingonratechangeonseekedonseekingonstalledonstoponsuspendontimeupdateonvolumechangeonwaiting
焦点FocusEventArgsonfocus, onblur, onfocusin, onfocusout不包含对 relatedTarget 的支持。
输入ChangeEventArgsonchangeoninput
键盘KeyboardEventArgsonkeydown, onkeypress, onkeyup
鼠标MouseEventArgsonclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
鼠标指针PointerEventArgsonpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
鼠标滚轮WheelEventArgsonwheelonmousewheel
进度ProgressEventArgsonabort, onload, onloadend, onloadstart, onprogress, ontimeout
触控TouchEventArgsontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancelTouchPoint 表示触控敏感型设备上的单个接触点。

有关更多信息,请参见以下资源:

Lambda 表达式Lambda expressions

还可以使用 Lambda 表达式

  1. <button @onclick="@(e => Console.WriteLine("Hello, world!"))">Say hello</button>

关闭附加值通常很方便,例如在循环访问一组元素时。下面的示例创建了三个按钮。在 UI 中选中这些按钮时,每个按钮都调用 UpdateHeading传递事件参数 (MouseEventArgs) 和其按钮编号 (buttonNumber):

  1. <h2>@_message</h2>
  2. @for (var i = 1; i < 4; i++)
  3. {
  4. var buttonNumber = i;
  5. <button class="btn btn-primary"
  6. @onclick="@(e => UpdateHeading(e, buttonNumber))">
  7. Button #@i
  8. </button>
  9. }
  10. @code {
  11. private string _message = "Select a button to learn its position.";
  12. private void UpdateHeading(MouseEventArgs e, int buttonNumber)
  13. {
  14. _message = $"You selected Button #{buttonNumber} at " +
  15. $"mouse position: {e.ClientX} X {e.ClientY}.";
  16. }
  17. }

备注

不要在 Lambda 表达式中直接使用 for 循环中的循环变量 (i) 。否则,所有 Lambda 表达式将使用相同的变量,导致所有 Lambda 中的 i 值相同。始终在本地变量中捕获其值(在前面的示例中为 buttonNumber),然后使用它。

EventCallbackEventCallback

嵌套组件的一个常见场景:希望在子组件事件发生时运行父组件的方法 — 例如当子组件中发生 onclick 事件时。若要跨组件公开事件,请使用 EventCallback父组件可向子组件的 EventCallback 分配回调方法。

示例应用 (Components/ChildComponent.razor) 中的 ChildComponent 演示如何设置按钮的 onclick 处理程序以从示例的 ParentComponent 接收 EventCallback 委托 。EventCallback 是用 MouseEventArgs 键入的,这适用于来自外围设备的 onclick 事件:

  1. <div class="panel panel-default">
  2. <div class="panel-heading">@Title</div>
  3. <div class="panel-body">@ChildContent</div>
  4. <button class="btn btn-primary" @onclick="OnClickCallback">
  5. Trigger a Parent component method
  6. </button>
  7. </div>
  8. @code {
  9. [Parameter]
  10. public string Title { get; set; }
  11. [Parameter]
  12. public RenderFragment ChildContent { get; set; }
  13. [Parameter]
  14. public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
  15. }

ParentComponent 将子级的 EventCallback<T> (OnClickCallback) 设置为其 ShowMessage 方法。

Pages/ParentComponent :

  1. @page "/ParentComponent"
  2. <h1>Parent-child example</h1>
  3. <ChildComponent Title="Panel Title from Parent"
  4. OnClickCallback="@ShowMessage">
  5. Content of the child component is supplied
  6. by the parent component.
  7. </ChildComponent>
  8. <p><b>@_messageText</b></p>
  9. @code {
  10. private string _messageText;
  11. private void ShowMessage(MouseEventArgs e)
  12. {
  13. _messageText = $"Blaze a new trail with Blazor! ({e.ScreenX}, {e.ScreenY})";
  14. }
  15. }

ChildComponent 中选择该按钮时:

  • 调用 ParentComponentShowMessage 方法。_messageText 更新并显示在 ParentComponent 中。
  • 回调方法 (ShowMessage) 中不需要对 StateHasChanged 的调用。自动调用 StateHasChanged 以重新呈现 ParentComponent,就像子事件触发组件重新呈现于在子级中执行的事件处理程序中一样。

EventCallbackEventCallback<T> 允许异步委托。EventCallback<T> 为强类型,需要特定的参数类型。EventCallback 为弱类型,允许任何参数类型。

  1. <ChildComponent
  2. OnClickCallback="@(async () => { await Task.Yield(); _messageText = "Blaze It!"; })" />

使用 InvokeAsync 调用 EventCallbackEventCallback<T> 并等待 Task

  1. await callback.InvokeAsync(arg);

使用 EventCallbackEventCallback<T> 处理事件和绑定组件参数。

优先使用强类型 EventCallback<T> 而非 EventCallbackEventCallback<T> 向用户提供更好的组件错误反馈。与其他 UI 事件处理程序类似,指定事件参数是可选操作。当没有值传递给回调时,使用 EventCallback

阻止默认操作Prevent default actions

使用 @on{EVENT}:preventDefault 指令属性可阻止事件的默认操作。

在输入设备上选择某个键并且元素焦点位于某个文本框上时,浏览器通常在该文本框中显示该键的字符。在下面的示例中,通过指定 @onkeypress:preventDefault 指令属性来阻止默认行为。计数器递增,且 + 键不会捕获到 <input> 元素的值中 :

  1. <input value="@_count" @onkeypress="KeyHandler" @onkeypress:preventDefault />
  2. @code {
  3. private int _count = 0;
  4. private void KeyHandler(KeyboardEventArgs e)
  5. {
  6. if (e.Key == "+")
  7. {
  8. _count++;
  9. }
  10. }
  11. }

指定没有值的 @on{EVENT}:preventDefault 属性等同于 @on{EVENT}:preventDefault="true"

属性的值也可以是表达式。在下面的示例中,_shouldPreventDefault 是设置为 truefalsebool 字段:

  1. <input @onkeypress:preventDefault="_shouldPreventDefault" />

不需要事件处理程序来阻止默认操作。事件处理程序和阻止默认操作场景可以独立使用。

停止事件传播Stop event propagation

使用 @on{EVENT}:stopPropagation 指令属性来停止事件传播。

在下例中,选中复选框可阻止第二个子级 <div> 中的单击事件传播到父级 <div>

  1. <label>
  2. <input @bind="_stopPropagation" type="checkbox" />
  3. Stop Propagation
  4. </label>
  5. <div @onclick="OnSelectParentDiv">
  6. <h3>Parent div</h3>
  7. <div @onclick="OnSelectChildDiv">
  8. Child div that doesn't stop propagation when selected.
  9. </div>
  10. <div @onclick="OnSelectChildDiv" @onclick:stopPropagation="_stopPropagation">
  11. Child div that stops propagation when selected.
  12. </div>
  13. </div>
  14. @code {
  15. private bool _stopPropagation = false;
  16. private void OnSelectParentDiv() =>
  17. Console.WriteLine($"The parent div was selected. {DateTime.Now}");
  18. private void OnSelectChildDiv() =>
  19. Console.WriteLine($"A child div was selected. {DateTime.Now}");
  20. }