将焦点设置为 < input > element

我工作的角度5前端应用程序,我需要有一个搜索框隐藏,但在按钮点击,搜索框应显示和集中。

我已经尝试了在 StackOverflow 上找到的一些具有指令性的方法,但是不能成功。

下面是示例代码:

@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello</h2>
</div>
<button (click) ="showSearch()">Show Search</button>
<p></p>
<form>
<div >
<input *ngIf="show" #search type="text"  />
</div>
</form>
`,
})
export class App implements AfterViewInit {
@ViewChild('search') searchElement: ElementRef;


show: false;
name:string;
constructor() {
}


showSearch(){
this.show = !this.show;
this.searchElement.nativeElement.focus();
alert("focus");
}


ngAfterViewInit() {
this.firstNameElement.nativeElement.focus();
}

搜索框未设置为焦点。

我该怎么做?

327417 次浏览

编辑2022:
以更现代的方式阅读@Cichy 的回答


像这样修改 show 搜索方法

showSearch(){
this.show = !this.show;
setTimeout(()=>{ // this will make the execution after the above boolean has changed
this.searchElement.nativeElement.focus();
},0);
}

该指令将立即集中并选择元素中的任何文本,只要它显示出来。在某些情况下,这可能需要一个 setTimeout,因为它没有经过太多的测试。

import { Directive, ElementRef, OnInit } from '@angular/core';
    

@Directive({
selector: '[appPrefixFocusAndSelect]',
})
export class FocusOnShowDirective implements OnInit {
constructor(private el: ElementRef) {
if (!el.nativeElement['focus']) {
throw new Error('Element does not accept focus.');
}
}
    

ngOnInit(): void {
const input: HTMLInputElement = this.el.nativeElement as HTMLInputElement;
input.focus();
input.select();
}
}

在 HTML 中:

<mat-form-field>
<input matInput type="text" appPrefixFocusAndSelect [value]="'etc'">
</mat-form-field>

你应该使用 HTML 自动对焦:

<input *ngIf="show" #search type="text" autofocus />

注意: 如果您的组件被持久化和重用,那么它只会在第一次附加片段时自动对焦。这可以通过使用一个 全局 DOM 监听器来克服,该 全局 DOM 监听器在附加 DOM 片段时检查其内部的 autofocus 属性,然后通过 JavaScript 重新应用该属性或焦点。

下面是一个全局监听器的例子,它只需要在您的 spa 应用程序中放置一次,无论同一片段被重用多少次,autofocus 都会运行:

(new MutationObserver(function (mutations, observer) {
for (let i = 0; i < mutations.length; i++) {
const m = mutations[i];
if (m.type == 'childList') {
for (let k = 0; k < m.addedNodes.length; k++) {
const autofocuses = m.addedNodes[k].querySelectorAll("[autofocus]"); //Note: this ignores the fragment's root element
console.log(autofocuses);
if (autofocuses.length) {
const a = autofocuses[autofocuses.length - 1]; // focus last autofocus element
a.focus();
a.select();
}
}
}
}
})).observe(document.body, { attributes: false, childList: true, subtree: true });

要在布尔值更改后执行,并避免使用超时,可以这样做:

import { ChangeDetectorRef } from '@angular/core';


constructor(private cd: ChangeDetectorRef) {}


showSearch(){
this.show = !this.show;
this.cd.detectChanges();
this.searchElement.nativeElement.focus();
}

我将在这个(角度7解决方案)上发表意见

input [appFocus]="focus"....
import {AfterViewInit, Directive, ElementRef, Input,} from '@angular/core';


@Directive({
selector: 'input[appFocus]',
})
export class FocusDirective implements AfterViewInit {


@Input('appFocus')
private focused: boolean = false;


constructor(public element: ElementRef<HTMLElement>) {
}


ngAfterViewInit(): void {
// ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
if (this.focused) {
setTimeout(() => this.element.nativeElement.focus(), 0);
}
}
}

这是在没有 setTimeout 的 i Angular 8中工作的:

import {AfterContentChecked, Directive, ElementRef} from '@angular/core';


@Directive({
selector: 'input[inputAutoFocus]'
})
export class InputFocusDirective implements AfterContentChecked {
constructor(private element: ElementRef<HTMLInputElement>) {}


ngAfterContentChecked(): void {
this.element.nativeElement.focus();
}
}

说明: 好的,这个有效是因为: 变化检测。这和 setTimout 工作的原因是一样的,但是当以 Angular 运行 setTimeout 时,它会绕过 Zone.js 并再次运行所有检查,而且它工作的原因是当 setTimeout 完成时,所有的更改都完成了。使用正确的生命周期钩子(AfterContentChecked)可以得到相同的结果,但是其优点是不会运行额外的循环。当检查和传递所有更改时,该函数将触发,并在“ AfterContentInit”和“ DoCheck”挂钩之后运行。如果我错了,请纠正我。

更多关于生命周期和变化检测的信息

更新 : 我发现了一个更好的方法来做到这一点,如果一个是使用角度材料 CDK,a11y 包。 首先在模块中导入 A11yModule,声明您的 input-field 所在的组件。 然后使用 CdkTrapFocus自动捕获指令,在 html 中像这样使用,并在输入上设置 tabIndex:

<div class="dropdown" cdkTrapFocus cdkTrapFocusAutoCapture>
<input type="text tabIndex="0">
</div>

我们在定位和响应方面遇到了一些问题,于是开始使用 cdk 中的 OverlayModule,这种使用 A11yModule 的方法完美无缺。

更简单的方法也是这样做。

let elementReference = document.querySelector('<your css, #id selector>');
if (elementReference instanceof HTMLElement) {
elementReference.focus();
}

在角度,在 HTML 本身,你可以设置焦点输入点击一个按钮。

<button (click)="myInput.focus()">Click Me</button>


<input #myInput></input>

还有一个名为 cdkFocusInitial的 DOM 属性,它可以用于输入。 你可以在这里阅读更多相关 https://material.angular.io/cdk/a11y/overview

只使用角度模板

<input type="text" #searchText>


<span (click)="searchText.focus()">clear</span>

组件的 html:

<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">

元件控制器:

showSearch() {
this.show = !this.show;
}

. . 别忘了从 @ angle/cdk/a11y进口 A11yModule

import { A11yModule } from '@angular/cdk/a11y'

我有同样的情况,这对我有用,但我没有“隐藏/显示”功能,你有。因此,也许你可以首先检查当字段总是可见时是否获得焦点,然后尝试解决为什么在改变可见性时不起作用(可能这就是为什么你需要应用睡眠或承诺)

为了集中注意力,这是你唯一需要做的改变:

你的 HTML 格式输入应该是:

<input #yourControlName matInput>

在 TS 类中,在变量部分(

export class blabla...
@ViewChild("yourControlName") yourControl : ElementRef;

你的按钮没事,它在呼叫:

  showSearch(){
///blabla... then finally:
this.yourControl.nativeElement.focus();
}

就是这样。 你可以在我找到的这篇文章中检查这个解决方案,所以感谢—— > Https://codeburst.io/focusing-on-form-elements-the-angular-way-e9a78725c04f

使用叠加/对话框时,需要在 cdkTrapFocuscdkTrapFocusAutoCapture中使用 cdkFocusInitial

CDK 区域 :

如果将 cdkFocusInitialwith 与 CdkTrapFocus 指令一起使用,除非同时启用 cdkTrapFocusAutoCapture 选项,否则不会发生任何事情。这是由于缺省情况下 CdkTrapFocus 没有捕获初始化的焦点。

在叠加/对话框组件中:

<div cdkTrapFocus cdkTrapFocusAutoCapture>
<input cdkFocusInitial>
</div>