Angular2 +自动对焦输入元素

Mak*_*kla 42 typescript angular

如何自动对焦输入元素?与问题类似,但与AngularDart不同.像这样的东西:

<input type="text" [(ngModel)]="title" [focus] />
//or 
<input type="text" [(ngModel)]="title" autofocus />
Run Code Online (Sandbox Code Playgroud)

Angular2是否支持此功能?

最近的问题是这个问题,但是有没有更简单/更简单的解决方案,因为我没有"输入框列表".在提供的链接*ngFor="#input of inputs"中使用,但我在控件模板中只有1个输入.

Mak*_*kla 63

这是我目前的代码:

import { Directive, ElementRef, Input } from "@angular/core";

@Directive({
    selector: "[autofocus]"
})
export class AutofocusDirective
{
    private focus = true;

    constructor(private el: ElementRef)
    {
    }

    ngOnInit()
    {
        if (this.focus)
        {
            //Otherwise Angular throws error: Expression has changed after it was checked.
            window.setTimeout(() =>
            {
                this.el.nativeElement.focus(); //For SSR (server side rendering) this is not safe. Use: https://github.com/angular/angular/issues/15008#issuecomment-285141070)
            });
        }
    }

    @Input() set autofocus(condition: boolean)
    {
        this.focus = condition !== false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用例:

[autofocus] //will focus
[autofocus]="true" //will focus
[autofocus]="false" //will not focus
Run Code Online (Sandbox Code Playgroud)

过时的代码(旧答案,以防万一):
我最终得到了这段代码:

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

@Directive({
    selector: '[autofocus]'
})
export class Autofocus
{
    constructor(private el: ElementRef, private renderer: Renderer)
    {        
    }

    ngOnInit()
    {        
    }

    ngAfterViewInit()
    {
        this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我把代码放在ngOnViewInit它不起作用.代码也使用最佳实践,因为不建议直接调用元素.

编辑(条件自动对焦):
几天前我需要条件自动对焦,因为我隐藏了第一个自动对焦元素,我想要聚焦另一个,但只有当第一个不可见时,我结束了这段代码:

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

@Directive({
    selector: '[autofocus]'
})
export class AutofocusDirective
{
    private _autofocus;
    constructor(private el: ElementRef, private renderer: Renderer)
    {
    }

    ngOnInit()
    {
    }

    ngAfterViewInit()
    {
        if (this._autofocus || typeof this._autofocus === "undefined")
            this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
    }

    @Input() set autofocus(condition: boolean)
    {
        this._autofocus = condition != false;
    }
}
Run Code Online (Sandbox Code Playgroud)

Edited2:
不推荐使用Renderer.invokeElementMethod,新的Renderer2不支持它.所以我们回到原生焦点(例如在DOM-SSR之外不起作用!).

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

@Directive({
    selector: '[autofocus]'
})
export class AutofocusDirective
{
    private _autofocus;
    constructor(private el: ElementRef)
    {
    }

    ngOnInit()
    {
        if (this._autofocus || typeof this._autofocus === "undefined")
            this.el.nativeElement.focus();      //For SSR (server side rendering) this is not safe. Use: https://github.com/angular/angular/issues/15008#issuecomment-285141070)
    }

    @Input() set autofocus(condition: boolean)
    {
        this._autofocus = condition != false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用例:

[autofocus] //will focus
[autofocus]="true" //will focus
[autofocus]="false" //will not focus
Run Code Online (Sandbox Code Playgroud)

  • 当我实现这个时,我得到了“ExpressionChangedAfterItHasBeenCheckedError”异常。我尝试在 .focus() 之后立即使用 detectorChanges() 但它不起作用。 (2认同)

Ham*_*pus 37

autofocus是一个本机html功能,至少应该用于页面初始化.然而,它无法与许多角度场景一起使用,尤其是使用*ngIf.

您可以制作一个非常简单的自定义指令来获得所需的行为.

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

@Directive({
  selector: '[myAutofocus]'
})
export class AutofocusDirective implements OnInit {

  constructor(private elementRef: ElementRef) { };

  ngOnInit(): void {
    this.elementRef.nativeElement.focus();
  }

}
Run Code Online (Sandbox Code Playgroud)

上述指令适用于我的用例.

如何使用

<input *ngIf="someCondition" myAutofocus />
Run Code Online (Sandbox Code Playgroud)

编辑:似乎有一些用例,在OnInit生命周期方法中尽早调用焦点.如果是这种情况,请OnAfterViewInit改为.


Mic*_*ang 15

以下指令适用于我使用Angular 4.0.1

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

@Directive({
  selector: '[myAutofocus]'
})
export class MyAutofocusDirective implements AfterViewInit {
  constructor(private el: ElementRef)
  {
  }
  ngAfterViewInit()
  {
    this.el.nativeElement.focus();
  }
}
Run Code Online (Sandbox Code Playgroud)

像这样用它:

<md-input-container>
    <input mdInput placeholder="Item Id" formControlName="itemId" name="itemId" myAutofocus>
</md-input-container>
Run Code Online (Sandbox Code Playgroud)

使用OnInit生命周期事件的选项对我不起作用.我也试过在另一个对我不起作用的答案中使用渲染器.


rin*_*usu 13

您可以为input元素指定模板引用变量#myInput:

<input type="text" [(ngModel)]="title" #myInput />
Run Code Online (Sandbox Code Playgroud)

让您的组件实现AfterViewInit,使用ViewChild注释获取input元素的引用,并将您的元素集中在ngAfterViewInit钩子中:

export class MyComponent implements AfterViewInit {
    @ViewChild("myInput") private _inputElement: ElementRef;

    [...]

    ngAfterViewInit(): void {
        this._inputElement.nativeElement.focus();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我宁愿看到基本方法(模板中的属性),所以我不需要在每个具有表单的页面中编写所有这些代码。 (2认同)
  • 无法读取未定义的属性“nativeElement” - 在控制台上出现错误 (2认同)

Ser*_*rin 12

<input type="text" [(ngModel)]="title" #myInput />
{{ myInput.focus() }}
Run Code Online (Sandbox Code Playgroud)

只需在模板内输入后添加{{myInput.focus()}}

  • 不是一个好的解决方案。这可能永远不会让控件失去焦点,因为角度会随着每次输入更改,鼠标悬停等来评估并应用焦点。 (3认同)

Tan*_*äär 8

如果您不需要真/假功能,但希望始终设置自动对焦,那么 Makla 的解决方案有一个更短的实现:

自动对焦.directive.ts:

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

@Directive({
    selector: '[autofocus]'
})

export class AutofocusDirective implements AfterViewInit {

    constructor(private el: ElementRef) {
    }

    ngAfterViewInit() {
        // Otherwise Angular throws error: Expression has changed after it was checked.
        window.setTimeout(() => {
            this.el.nativeElement.focus();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

用例:

<input autofocus> //will focus
Run Code Online (Sandbox Code Playgroud)

使用 AfterViewInit 而不是 OnInit 会使光标放置在输入字段内的内容之后(如果已填充)。

请记住在模块中声明导出自动对焦指令!