Angular 中的伪事件

2023-08-16 08:15:26 浏览数 (4)

原文 - Angular Pseudo-Events 作者 - Shijir Tsogoo

Angular 提供了一个巧妙的小功能,用于简化监听键盘事件的过程。尽管在 Angular 模版绑定文档中提到了伪事件 pseudo-event,但是在其他地方没有进一步的文档说明。深入之前,我们看看 Angular 中的伪事件解决了什么问题。我们简单举个例子,假设你需要添加一个 UNDO 命令来切换复选框。UNDO 命令是恢复用户的上一个选择。

如同我们在自己电脑上执行 UNDO 指令一样,指令应该根据 CTRL Z 组合做出响应。下面的案例展示我们是怎么使用非伪事件实现的:

代码语言:javascript复制
// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  onKeydown(event: KeyboardEvent) {
    if(event.key == "z" && event.ctrlKey) {
      event.target.checked = !event.target.checked;
    }
  }
}

译者加:在 mac 平台上不起效

正如上面案例所示,我们监听 KeyboardEvent.key 来检查哪个按键被敲击。当然,还有很多 KeyboardEvent 的属性可以用来检查和捕获按键,比如 KeyboardEvent.key, KeyboardEvent.charCode, KeyboardEvent.keyCode 或者 KeyboardEvent.which。然而,它们中有些是被抛弃或者浏览器并不支持。并且,我们监听的组合键越多,语法越复杂。

Angular 伪事件将解决上面的担忧。通过伪事件,Angular 允许你直接绑定指定按键或者按键组合。这意味着,键盘事件只会通过特定键或者组合键上触发,而不是所有键盘事件上都触发。如下,是一个关于怎么在模版中声明伪事件的例子:

代码语言:javascript复制
<input (keyup.enter) ='...responds to enter...' />

<input (keydown.esc) ='...responds to escape...' />

<input (keyup.shift.f) ='...responds to shift f...' />

现在,让我们看看伪事件如何帮助我们监听 CTRL Z 键盘组合:

代码语言:javascript复制
// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  toggle(checkbox: HTMLElement) {
    checkbox.checked = !checkbox.checked;
  }
}

正如你所见,我们不再需要检查哪些按键事件被注册,因为我们制定了处理程序的应该响应的组合键,而且语法变得更加声明性。

在 @HostListener 中使用 Pseudo-Events

如同其他 DOM 事件,你可以通过 @HostListener 监听伪事件:

代码语言:javascript复制
@HostListener('keydown.control.z') 
undo(event: KeyboardEvent) {
  // responds to control z
}

当然,如果宿主元素不可获取焦点,或者无论事件来自何处,你都要捕获键盘事件,你可以将事件绑定到全局元素,比如:

代码语言:javascript复制
@HostListener('document:keydown.control.z')
undo(event: KeyboardEvent) {
  // responds to control z
}

Pseudo-Events 的键名

现在,我们看看键组合伪事件的例子:

代码语言:javascript复制
<input (keydown.control.shift.z)='...' />

你可能疑惑这些键名(比如: control, shiftz)来自哪里?它们并不是 Angular 伪元素独有的。实际上,它们是 KeyboardEvent 小写的键属性。如果你想查键盘事件属性值完整的列表,请移步参考。现在,让我们来查看一下可用于 Angular 伪事件的键值。

Modifier Keys

修饰键(Modifier Keys)包括 ShiftControlAlt(Option)Meta(Command)。从现在开始,我们会把其他键称为非修饰键。修饰键伪事件的示例如下:

代码语言:javascript复制
<input (keyup.control)='...respond to ctrl/control...' />

<input (keyup.alt)='...respond to alt/option...' />

<input (keyup.shift)='...respond to shift...' />

<input (keyup.meta)='...respond to command...' />

Angular 中使用伪事件,有几个点需要我们记住。

第一,任何组合键都必须有至少一个修饰键,但是只有一个非修饰键。 比如,下面的案例将不会起作用,因为组合键只是由字母组成:

代码语言:javascript复制
<input (keyup.a.z)='...responds to a z...' />

第二,非组合键必须放在组合键的最后定义。 下面是一个正确的放置案例,因为非修饰键 Z 放在最后定义:

代码语言:javascript复制
<input (**keydown.control.z**)='...responds to control z...' />

相比之下,下面这个例子中修饰键放置的位置不对:

代码语言:javascript复制
<input (keydown.z.control)='...won't respond at all...' />

第三,修饰键之间的顺序并不影响。 所以,我们可以根据自己的需要放置。下面的案例展示了有效的用例:

代码语言:javascript复制
<input (**keydown.shift.control.z**)='...responds to shift control z...' /> 

<input (**keydown.control.shift.z**)='...responds to control shift z...' />

接下来,我们看看非修饰键的示例。

Functional keys
代码语言:javascript复制
<input (keyup.f5)='...responds to F5...' />

<input (keyup.f12)='...responds to F12...' />
Number 和 letter keys
代码语言:javascript复制
<input (keyup.0)='...responds to 0...' />

<input (keyup.9)='...responds to 9...' />

<input (keyup.a)='...responds to a...' />

<input (keyup.z)='...responds to z...' />
Arrow keys
代码语言:javascript复制
<input (**keyup.arrowup**)='...responds to arrowup...' />  
  
<input (**keyup.arrowright**)='...responds to arrowright...' />

Other keys

代码语言:javascript复制
<input (keyup.enter)='...responds to enter...' />

<input (keyup.esc)='...responds to escape...' /> 

<input (keyup.escape)='...responds to escape...' />

<input (keyup.backspace)='...responds to backspace...' />

<input (keyup.tab)='...responds to tab...' />

到目前,只有两个键没提及:DotSpace。当你点击 dot 键的时候,KeyboardEvent.key 的属性值是 "."。但是,我们可以想象下,如果在伪事件中使用点作为分隔符,它在语法上是不正确的。这就是为什么它被映射为 "dot" 关键字。所以,我们需要按照下面的方式正确监听 Dot 按键:

代码语言:javascript复制
<input (**keydown.dot**)='...responds to dot...'/>

而不是...

代码语言:javascript复制
<input (keydown.. )='...won't respond at all...'/>

Space 按键同理。因为它的 KeyboardEvent.key 是空 "",映射为 "space" 关键字可读性更高。所以不是这种写法:

代码语言:javascript复制
<input (keydown. )='...won't respond at all...'/>

而是:

代码语言:javascript复制
<input (keydown.space)='...won't respond at all...'/>

不幸的是,Angular 伪事件在大多数字符号键(如减号,等号,斜杆,左括号,右括号,反向号等)上仍然缺乏这种映射。由于它们是符号键,这导致非常差的可读性,有时候会破坏绑定本身。例如,我们想监听 Minus 减号按键,我们只能按照下面这种方式进行:

代码语言:javascript复制
<input (keydown.-)='...responds to minus...'/>

正如你所见,这看起来很怪异或者语法错误,但是它可行。如果它映射成 "minus" 可读性更高。等号按键呢?

代码语言:javascript复制
<input (keydown.=)='...breaks the binding...'/>

如果你尝试按照上面的方式监听 Equal 等号按键,它会破坏我们模版绑定,因为它没有与之对应的 "equal" 关键字映射。

尽管符号键存在一些小缺点,但是 Angular 伪事件是一个非常棒的功能,能够满足大多数监听键盘事件的需求。我相信在任何 Angular 应用中使用它可以使实现键盘辅助功能和交互的过程更加简单。

阅读本文后,我希望你已经对 Angular 伪事件有一定的了解。

译者加:某些伪事件在平台上绑定有一定差异,比如在 mac 上绑定 document:keydown.control.arrowright 不生效,在 window 上则生效

0 人点赞