【问题标题】:angular ngAfterViewInit element focus not workin角度 ngAfterViewInit 元素焦点不起作用
【发布时间】:2021-06-16 14:48:33
【问题描述】:

在加载组件时,我希望您在初始化后专注于第一个元素。我找到了一个教程,但它不适合我。

https://davidmcintosh.medium.com/auto-focusing-an-angular-input-the-easy-way-part-1-dcb1799e025f

但如果我把它放在一个为 0 的计时器中,那么它会很好用。但我不想使用计时器。

ngAfterViewInit(): void {
    timer(0).subscribe(() => this.firstElement.nativeElement.focus());
}

为什么我需要一个价值如此荒谬的计时器?

这是我的 HTML 代码:

<p class="news-title" tabindex="0" #firstElement>{{ 'news.title' | translate }}</p>
<ul class="news-list" role="list">
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-1' | translate }}</li>
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-2' | translate }}</li>
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-3' | translate }}</li>
</ul>

【问题讨论】:

  • ngAfterViewInit 在通常的更改检测周期完成后执行。如果你在ngAfterViewInit 中执行一些状态更新,你会得到可怕的ExpressionChangedAfterIthasBeenChecked 错误。所以几乎每个人都会在其中执行 settimeout(..., 0) 的变体来执行额外的操作。在这种特殊情况下,鉴于您没有执行更改组件状态的操作,我会说使用timer(0) 没有读取差异。顺便说一句,focus 通常在input 元素上执行。您希望在&lt;p&gt; 上试用它吗?
  • 我需要专注,因为可访问性。
  • 嗯,在 JavaScript 中需要使用 settimeout(function, 0) 是很正常的。这是常见的做法,而且一直如此。您可以在组件中试验ViewChild 的选项(在您发布的 sn-p 中不存在)。我想您只是不能在创建 DOM 节点的同一滴答声中调用焦点,但这只是一个猜想。
  • 我建议改为查看用于处理此问题的 angular a11y accessibility cdk 指令,例如 cdkFocusInitial 而不是半生不熟的东西。

标签: angular typescript settimeout


【解决方案1】:

它对我有用,因为你的 &lt;p&gt; 标签是静态的,它会一直存在,你可以用{static: true} 查询viewChild,这种情况下它会在更改检测之前查询元素,请参阅stackblitz

  @ViewChild('firstElement', {read: ElementRef, static: true})
  firstElement?: ElementRef<unknown>;

  ngAfterViewInit(): void {
    (this.firstElement?.nativeElement as any).focus();
  }

更好的解决方案是使用材料的 A11y CDK cdkTrapFocusAutoCapture,请参阅 stackblitz

<p cdkTrapFocus="false" cdkTrapFocusAutoCapture class="news-title" tabindex="0" #firstElement>{{ 'news.title' }}</p>
<ul class="news-list" role="list">
  <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-1' }}</li>
  <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-2' }}</li>
  <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-3' }}</li>
</ul>

注意:

  • 焦点只能集中在可聚焦的元素上
  • 请注意是否是您的翻译管道引入了计时问题,如果您使用的是 transloco 可能会尝试使用 transloco 结构指令而不是管道。

【讨论】:

  • @BálintBakos 您是如何解决问题的?今天我重新考虑,即使没有 {static: true} ngAfterViewInit 也应该可以正常工作。 {static: true} 有助于在 DetectionChange 之前查询 viewChild,但您在 ViewInit 之后设置焦点,一切都应该正常工作。您的翻译管道是否导致时间问题?
  • cdkTrapFocusAutoCapture 是救命稻草,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-25
  • 2015-06-12
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-19
相关资源
最近更新 更多