将焦点放在 <input> 元素上
Set focus on <input> element
我正在使用 Angular 5 开发一个前端应用程序,我需要隐藏一个搜索框,但在单击按钮时,搜索框应该会显示并获得焦点。
我尝试了一些在 Whosebug 上找到的带有指令的方法,但都没有成功。
示例代码如下:
@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();
}
搜索框没有设置焦点。
我该怎么做?
像这样修改显示搜索方法
showSearch(){
this.show = !this.show;
setTimeout(()=>{ // this will make the execution after the above boolean has changed
this.searchElement.nativeElement.focus();
},0);
}
该指令将立即聚焦并 select 元素中的任何文本一经显示。在某些情况下这可能需要一个 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 />
注意:如果您的组件被保留并重复使用,它只会在第一次附加片段时自动对焦。这可以通过 global DOM listener 来克服,该 global DOM listener 在 DOM 片段附加时检查自动对焦属性,然后重新应用它或通过 JavaScript.
聚焦
这是一个全局监听器示例,它只需要在您的 spa 应用程序中放置一次,无论同一个片段被重复使用多少次,自动对焦都会起作用:
(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();
}
我将对此进行权衡(Angular 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);
}
}
}
这在 Angular 8 没有 setTimeout:
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 是complete 所有更改都已完成。使用正确的生命周期钩子 (AfterContentChecked) 可以达到相同的结果,但优点是额外的周期不会 运行。该函数将在检查并通过所有更改时触发,并且在钩子 AfterContentInit 和 DoCheck 之后 运行s。如果我这里说错了请指正。
https://angular.io/guide/lifecycle-hooks
上的更多生命周期和变更检测
更新:
如果使用 Angular Material CDK,即 a11y 包,我发现了一种更好的方法。
首先在模块中导入 A11yModule ,声明您在其中具有输入字段的组件。
然后使用 cdkTrapFocus 和 cdkTrapFocusAutoCapture 指令并在 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();
}
在 Angular 中,在 HTML 本身中,您可以将焦点设置为在单击按钮时输入。
<button (click)="myInput.focus()">Click Me</button>
<input #myInput></input>
还有一个名为 cdkFocusInitial
的 DOM 属性,它适用于我的输入。
您可以在这里阅读更多相关信息:https://material.angular.io/cdk/a11y/overview
仅使用 Angular 模板
<input type="text" #searchText>
<span (click)="searchText.focus()">clear</span>
html 的组件:
<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">
组件控制器:
showSearch() {
this.show = !this.show;
}
..并且不要忘记导入 A11yModule from @angular/cdk/a11y
import { A11yModule } from '@angular/cdk/a11y'
我有同样的情况,这对我有用,但我没有你拥有的“hide/show”功能。因此,也许您可以先检查当字段始终可见时是否获得焦点,然后尝试解决为什么在更改可见性时不起作用(可能这就是为什么您需要应用睡眠或承诺)
要设置焦点,这是您需要做的唯一更改:
你的 Html 垫输入应该是:
<input #yourControlName matInput>
在你的 TS class 中,在变量部分这样引用(
export class blabla...
@ViewChild("yourControlName") yourControl : ElementRef;
你的按钮没问题,呼叫:
showSearch(){
///blabla... then finally:
this.yourControl.nativeElement.focus();
}
就是这样。
您可以在我找到的 post 上查看此解决方案,因此感谢 -->
https://codeburst.io/focusing-on-form-elements-the-angular-way-e9a78725c04f
我正在使用 Angular 5 开发一个前端应用程序,我需要隐藏一个搜索框,但在单击按钮时,搜索框应该会显示并获得焦点。
我尝试了一些在 Whosebug 上找到的带有指令的方法,但都没有成功。
示例代码如下:
@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();
}
搜索框没有设置焦点。
我该怎么做?
像这样修改显示搜索方法
showSearch(){
this.show = !this.show;
setTimeout(()=>{ // this will make the execution after the above boolean has changed
this.searchElement.nativeElement.focus();
},0);
}
该指令将立即聚焦并 select 元素中的任何文本一经显示。在某些情况下这可能需要一个 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 />
注意:如果您的组件被保留并重复使用,它只会在第一次附加片段时自动对焦。这可以通过 global DOM listener 来克服,该 global DOM listener 在 DOM 片段附加时检查自动对焦属性,然后重新应用它或通过 JavaScript.
聚焦这是一个全局监听器示例,它只需要在您的 spa 应用程序中放置一次,无论同一个片段被重复使用多少次,自动对焦都会起作用:
(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();
}
我将对此进行权衡(Angular 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);
}
}
}
这在 Angular 8 没有 setTimeout:
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 是complete 所有更改都已完成。使用正确的生命周期钩子 (AfterContentChecked) 可以达到相同的结果,但优点是额外的周期不会 运行。该函数将在检查并通过所有更改时触发,并且在钩子 AfterContentInit 和 DoCheck 之后 运行s。如果我这里说错了请指正。
https://angular.io/guide/lifecycle-hooks
上的更多生命周期和变更检测更新: 如果使用 Angular Material CDK,即 a11y 包,我发现了一种更好的方法。 首先在模块中导入 A11yModule ,声明您在其中具有输入字段的组件。 然后使用 cdkTrapFocus 和 cdkTrapFocusAutoCapture 指令并在 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();
}
在 Angular 中,在 HTML 本身中,您可以将焦点设置为在单击按钮时输入。
<button (click)="myInput.focus()">Click Me</button>
<input #myInput></input>
还有一个名为 cdkFocusInitial
的 DOM 属性,它适用于我的输入。
您可以在这里阅读更多相关信息:https://material.angular.io/cdk/a11y/overview
仅使用 Angular 模板
<input type="text" #searchText>
<span (click)="searchText.focus()">clear</span>
html 的组件:
<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">
组件控制器:
showSearch() {
this.show = !this.show;
}
..并且不要忘记导入 A11yModule from @angular/cdk/a11y
import { A11yModule } from '@angular/cdk/a11y'
我有同样的情况,这对我有用,但我没有你拥有的“hide/show”功能。因此,也许您可以先检查当字段始终可见时是否获得焦点,然后尝试解决为什么在更改可见性时不起作用(可能这就是为什么您需要应用睡眠或承诺)
要设置焦点,这是您需要做的唯一更改:
你的 Html 垫输入应该是:
<input #yourControlName matInput>
在你的 TS class 中,在变量部分这样引用(
export class blabla...
@ViewChild("yourControlName") yourControl : ElementRef;
你的按钮没问题,呼叫:
showSearch(){
///blabla... then finally:
this.yourControl.nativeElement.focus();
}
就是这样。 您可以在我找到的 post 上查看此解决方案,因此感谢 --> https://codeburst.io/focusing-on-form-elements-the-angular-way-e9a78725c04f