【问题标题】:How to use Angular4 to set focus by element id如何使用Angular4通过元素ID设置焦点
【发布时间】:2018-03-25 00:58:44
【问题描述】:

我是 Angular 的新手,我正在尝试使用它来将焦点放在 ID 为“input1”的输入上。我正在使用以下代码:

@ViewChild('input1') inputEl: ElementRef;

然后在组件中:

 this.inputEl.nativeElement.focus();

但它不起作用。我究竟做错了什么?任何帮助将不胜感激。

【问题讨论】:

  • 输入是作为 PrimeNg 模板的一部分动态生成的。我使用 jquery 在元素上设置 id,但我不知道如何在其上设置 [focus]。还有其他方法吗?
  • 谢谢@Z.Bagley!您提到的问题中的一个答案有解决方案。

标签: angular angular-forms


【解决方案1】:

组件

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

@ViewChild('input1', {static: false}) inputEl: ElementRef;
    
ngAfterViewInit() {
   setTimeout(() => this.inputEl.nativeElement.focus());
}

HTML

<input type="text" #input1>

【讨论】:

  • 您能解释一下为什么需要 setTimeout 吗?如果代码在视图被初始化之后运行,这似乎违反直觉。这是一个常见的陷阱吗?
  • @ANeves Stijn Van Bael 添加了setTimeout() 以防止ExpressionChangedAfterItHasBeenCheckedError
  • @DmitryGrinko - setTimout() 增加了一点延迟,因此焦点将转到下一个字段,然后再次回到前一个字段之前的下一个字段。我们有任何替代 setTimout() 的方法吗?
  • @Shree 移除 setTimeout,如果出现该错误,请尝试寻找其他解决方案。有很多关于这个错误的信息。不幸的是,我没有太多时间重现这个案例。
  • @DmitryGrinko 在我发表评论后几个小时,您似乎已经这样做了。
【解决方案2】:

@Z.Bagley 提到的问题中的一个答案给了我答案。我必须将 Renderer2 从 @angular/core 导入到我的组件中。那么:

const element = this.renderer.selectRootElement('#input1');
setTimeout(() => element.focus(), 0);

感谢@MrBlaise 的解决方案!

【讨论】:

  • setTimeout 是这里的关键。您还可以通过使用 ViewChild 注释对 ElementRef 属性进行注释,然后引用该 ElementRef 的“nativeElement”属性来获取没有渲染器的元素。
  • @GreyBeardedGeek 虽然使用 ElementRef 存在 XSS 安全风险,但 Dwight 的解决方案可能更安全。见:angular.io/api/core/ElementRef
  • 注意这一点也很有用:github.com/angular/angular/issues/15674
【解决方案3】:

经过一番搜索,我也遇到了同样的问题,我找到了一个很好的解决方案,因为@GreyBeardedGeek 提到 setTimeout 是这个解决方案的关键。他是完全正确的。在您的方法中,您只需要添加 setTimeout 即可解决您的问题。

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

【讨论】:

    【解决方案4】:

    这是一个 Angular4+ 指令,您可以在任何组件中重复使用它。基于 Niel T 在this question 的答案中给出的代码。

    import { NgZone, Renderer, Directive, Input } from '@angular/core';
    
    @Directive({
        selector: '[focusDirective]'
    })
    export class FocusDirective {
        @Input() cssSelector: string
    
        constructor(
            private ngZone: NgZone,
            private renderer: Renderer
        ) { }
    
        ngOnInit() {
            console.log(this.cssSelector);
            this.ngZone.runOutsideAngular(() => {
                setTimeout(() => {
                    this.renderer.selectRootElement(this.cssSelector).focus();
                }, 0);
            });
        }
    }
    

    您可以像这样在组件模板中使用它:

    <input id="new-email" focusDirective cssSelector="#new-email"
      formControlName="email" placeholder="Email" type="email" email>
    

    给输入一个 id 并将 id 传递给指令的cssSelector 属性。或者你可以传递任何你喜欢的 cssSelector。

    来自 Niel T 的评论:

    因为我唯一要做的就是将焦点放在一个元素上,所以我 不需要关心变化检测,所以我实际上可以 在 Angular 之外运行对 renderer.selectRootElement 的调用。因为 我需要给新的部分时间来渲染,元素部分是 包裹在超时中以允许渲染线程有时间赶上 在尝试选择元素之前。一旦一切就绪,我 可以使用基本的 CSS 选择器简单地调用元素。

    【讨论】:

      【解决方案5】:

      这对我有帮助(在离子中,但想法是一样的) https://mhartington.io/post/setting-input-focus/

      在模板中:

      <ion-item>
            <ion-label>Home</ion-label>
            <ion-input #input type="text"></ion-input>
      </ion-item>
      <button (click)="focusInput(input)">Focus</button>
      

      在控制器中:

        focusInput(input) {
          input.setFocus();
        }
      

      【讨论】:

        【解决方案6】:

        这是一个可以在任何组件中使用的指令:

        import { NgZone, Directive, ElementRef, AfterContentInit, Renderer2 } from '@angular/core';
        
        @Directive({
            selector: '[appFocus]'
        })
        export class FocusDirective implements AfterContentInit {
            constructor(private el: ElementRef, private zone: NgZone, private renderer: Renderer2) {}
        
            ngAfterContentInit() {
                this.zone.runOutsideAngular(() => setTimeout(() => {
                    this.renderer.selectRootElement(this.el.nativeElement).focus();
                }, 0));
            }
        }
        

        用途:

        <input type="text" appFocus>
        

        【讨论】:

          【解决方案7】:

          添加你的组件

          ngOnInit(): void {
              document?.getElementById("elementToGiveFocus")?.focus();
          }
          

          【讨论】:

            【解决方案8】:

            您可以简单地使用scrollIntoView,如下例所示,并随时调用该方法。

            <div id="elementID"></div>
            
            ngAfterViewInit(): void 
            {
                const element = document.querySelector("#elementID");
                element.scrollIntoView(true);
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-01-06
              • 1970-01-01
              • 2020-03-27
              • 2011-01-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多