Angular 如何使用绑定设置元素的焦点?

Angular 如何使用绑定设置元素的焦点?,angular,Angular,在Angular2中,如何在元素焦点上设置绑定。 我不想用elementRef设置它。 我认为在AngularJS中有ngFocus指令 在Angular2中没有此类指令使用Angular2在元素上设置焦点的最佳方法是使用渲染器并调用元素上的方法。如果没有elementRef,则无法执行此操作 这会导致如下结果: this.renderer.invokeElementMethod(this.input.nativeElement, 'focus', []); const element = t

在Angular2中,如何在元素焦点上设置绑定。 我不想用elementRef设置它。 我认为在AngularJS中有ngFocus指令
在Angular2中没有此类指令

使用Angular2在元素上设置焦点的最佳方法是使用
渲染器
并调用元素上的方法。如果没有
elementRef
,则无法执行此操作

这会导致如下结果:

this.renderer.invokeElementMethod(this.input.nativeElement, 'focus', []);
const element = this.renderer.selectRootElement('#elementId');

其中
renderer
使用
protectedrenderer:renderer

一个简单的“focus”指令注入构造函数

从'angular2/core'导入{指令,输入,ElementRef};
@指示({
选择器:“[焦点]”
})
类焦点指示{
@输入()
焦点:布尔;
构造函数(@Inject(ElementRef)private元素:ElementRef){}
受保护的ngOnChanges(){
this.element.nativeElement.focus();
}
}
//用法
@组成部分({
选择器:“应用程序”,
模板:`
移动焦点
`,
指令:[焦点指令]
})
导出类应用程序{
私有inputFocused=false;
moveFocus(){
this.inputFocused=true;
//我们需要这个,因为什么都不会
//在下一个方法调用时发生,
//仅当值发生更改时,才会调用指令中的ngOnChanges,
//所以我们必须以异步方式重置这个值,
//这很难看,但很管用
setTimeout(()=>{this.inputFocused=false});
}
}
更简单的方法:

import { Directive, ElementRef, Renderer} from "@angular/core";
@Directive({
    selector: "[Focus]"
})

export class myFocus {
    constructor(private _el: ElementRef, private renderer: Renderer) {
        this.renderer.invokeElementMethod(this._el.nativeElement, 'focus');
    }

}

我尝试了两种变体,但都不适合简单使用。第一个(通过@AngJobs)需要在使用指令(设置焦点=true)的组件中进行额外的工作,第二个(通过@ShellZero)根本不工作,因为在视图实际就绪之前调用了焦点。因此,我将焦点调用移动到
ngAfterViewInit
。现在您可以添加
,它对我有效,但在控制台中有错误。
在调试和搜索后,我们发现了这篇文章:

复制粘贴即可。它对我非常有效

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

@Directive({selector: '[focus]'})
export class FocusDirective implements AfterViewInit, DoCheck {
    private lastVisible: boolean = false;
    private initialised: boolean = false;

    constructor(private el: ElementRef) {
    }

    ngAfterViewInit() {
        console.log('inside FocusDirective.ngAfterViewInit()');
        this.initialised = true;
        this.ngDoCheck();
    }

    ngDoCheck() {

        console.log('inside FocusDirective.ngDoCheck()');

        if (!this.initialised) {
            return;
        }
        const visible = !!this.el.nativeElement.offsetParent;
        if (visible && !this.lastVisible) {
            setTimeout(() => {
                this.el.nativeElement.focus();
            }, 1);
        }
        this.lastVisible = visible;
    }
}
渲染器服务现在是(从Angular 4.x开始) 新的RenderR2服务没有invokeElementMethod。 您可以做的是获得对元素的引用,如下所示:

this.renderer.invokeElementMethod(this.input.nativeElement, 'focus', []);
const element = this.renderer.selectRootElement('#elementId');
然后你可以用它来关注这个元素,就像这样:

element.focus();
有关
selectRootElement
工作原理的更多信息:

编辑:

如果元素没有得到关注,常见的问题是元素没有准备好。(例如:禁用、隐藏等)。您可以这样做:

setTimeout(() => element.focus(), 0);

这将创建一个将在下一个VM回合中运行的宏任务,因此如果启用该元素,焦点将正常运行。

我从@MrBlaise获取了setTimeout片段,该片段为我完成了以下工作

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

@Directive({
 selector: '[autoFocus]',
})
export class FocusDirective implements AfterViewChecked {

  constructor(private _elementRef: ElementRef) { }

  ngAfterViewChecked() {
    this._elementRef.nativeElement.focus()
  }

}
<input type="text" #searchInput />



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

...

@ViewChild('searchInput') private searchInput: ElementRef;

...

setTimeout(() => this.searchInput.nativeElement.focus(), 0);

从“@angular/core”导入{ElementRef,ViewChild};
...
@ViewChild(“searchInput”)私有searchInput:ElementRef;
...
setTimeout(()=>this.searchInput.nativeElement.focus(),0);

诀窍是同时使用焦点和选择:

this.(element).nativeElement.focus();
this.(element).nativeElement.select();


我认为更好的方法是编写自己的ngFocus指令来操作元素,而不是在组件类中进行操作。。代码保持不变,但为什么Angular2团队没有创建它呢?因为每个人都想要一个稍微不同的实现。通过这种方式,你可以自己实现它,学习更多关于angular2A的知识。不要直接使用
nativeElement
。这不是与webworkers一起保存的。
指令
属性已在RC 6中删除。您应该将
FocusDirective
移动到NgModule decorator的declarations属性。我有相同的要求,但是,我想在指令内移动setTimeout,在指令内使用setTimeout可以实现相同的功能吗?这非常适用于基于桌面的浏览器,但由于某些原因,不适用于基于移动设备的浏览器。你知道为什么吗?对我不起作用,因为在视图实际准备就绪之前调用了focus,然后你必须将它添加到ngOnInit()[角度生命周期挂钩]中,或者你必须订阅任何事件,以便“在事件发生时聚焦”。谢谢-这太棒了。尽管您的类名不一定需要前缀(正如您在
Dm
中所做的那样)。要应用前缀的关键位是选择器名称值。i、 e.
选择器:“[appFocus]”
。我想这会降低后续angular版本中发生碰撞的可能性,等等。请注意:
渲染器
已被弃用,angular团队不打算将
invokeElementMethod()
向前引入
Renderer2
。使用RenderR2.selectRootElement获得的元素引用与使用ViewChild获得的元素引用有何不同?我试图理解为什么使用ViewChild获取元素引用(假设我们将其分配给“abc”),然后使用abc.nativeElement.focus()设置元素的焦点会带来XSS安全风险,但使用RenderR2不会。此外,只有在使用组件访问其模板中的元素时,使用nativeElement才会带来安全风险吗,或者,在自定义指令中使用它对任何其他组件模板中的元素执行相同操作时,它是否也会带来安全风险?@user6860460使用renderer2或通过Angular提供给您的任何其他抽象可能更安全,因为您不直接使用DOM。但是,当您使用nativeElement时,您再次打开了风险。这个例子不适合这种情况。如果要使用renderr2的addClass或createElement等方法,而不是在原始DOM元素上执行,则认为这样更安全。阅读底部的警告。这意味着您应该尽可能使用Render2提供的API,但一旦访问nativeElement,这是一种风险。但是如果在Render2方法中访问nativeElement,您是否也会面临同样的风险?谢谢。@user6860460技术上是的。一旦你拥有了nativeElement,你可以用它做任何你想做的事情。类似于设置innerHTML参数d