如何将焦点设置到另一个输入?

Posted

技术标签:

【中文标题】如何将焦点设置到另一个输入?【英文标题】:How can I set focus to another input? 【发布时间】:2015-10-13 10:46:24 【问题描述】:

当某些事件发生时,我需要能够将焦点切换到输入元素。我如何在 Angular 2 中做到这一点?

例如:

<input (keyUp)="processKeyUp($event)"/>
<input (focusme)="alert('i am focused')"/>

我想在第一个按下某个键时聚焦第二个输入框。我想我需要使用自定义事件(sn-p 中的focusme),但我不知道在哪里或如何声明它,以及是否为其使用@Directive 注释,或者将其定义包含在不知何故的一个组件。总之,我被难住了。

更新

忘了提,我知道我可以通过在 html 中使用局部变量来做到这一点,但我希望能够从组件中做到这一点,并且我希望能够在触发 focusme 时执行复杂的逻辑事件,以便监听它的控件可以确定它是否适合他们。 谢谢!

【问题讨论】:

你不能只用自定义事件来扩展输入元素,你需要创建自己的自定义元素来包装一个可以触发 focusme 事件的输入控件,即 好的,一旦我收到事件,如何将焦点设置到自定义组件中的输入元素?你能在答案中提供一个例子吗? 查看***.com/a/34503163/215945 了解设置焦点在另一个元素上的几种不同方式/实现。 【参考方案1】:

您可以将第二个输入作为变量传递给第一个

例如

HTML

<!-- We pass focusable as a parameter to the processKeyUp function -->
<input (keyup)="processKeyUp($event, focusable)"/>

<!-- With #focusable we are creating a variable which references to the input -->
<input #focusable /> 

稍后在你的 js/ts 中

@Component(
  selector: 'plunker-app'
)
@View(
  templateUrl: 'main.html'
)
class PlunkerApp 

  constructor() 
  

  processKeyUp(e, el) 
    if(e.keyCode == 65)  // press A
      el.focus();
    
  

el 是原始元素,因此您可以在其上使用纯 javascript

这是plnkr,您可以看到它的工作原理。

希望对你有帮助。

【讨论】:

感谢您的回答,但我需要将焦点传递给另一个组件中的输入元素,因此一个组件触发事件,另一个组件作用于事件并将焦点设置为输入元素在里面。 你可以同时阅读这个帖子github.com/angular/angular/issues/3186 @AviadP.,如果您想要组件间通信,并且您的组件不是“相关的”(即没有祖先或后代模式),您可以将 EventEmitter 放入服务中,将服务注入两个组件,让一个组件触发事件,并让另一个组件(您要关注的那个)订阅它。这是an example。 由于某种原因,这个答案对我不起作用(在我的代码中使用 rc.3)。我还需要关注组件代码中的元素,而不仅仅是从 DOM 触发的事件,所以 the accepted answer from here 正是我所需要的。注意更新。他们有有用的提示。 在输入(反应形式)和 cleaveJS 中的验证非常有用【参考方案2】:

对于 DOM 元素的操作,请始终尝试使用指令。在这种情况下,您可以编写简单的指令。

为了从指令中访问 DOM,我们可以通过指令构造函数中的 ElementRef 注入宿主 DOM 元素的引用。

constructor(@Inject(ElementRef) private element: ElementRef) 

对于绑定值的变化检测,我们可以使用 ngOnChanges livecycle 方法。

protected ngOnChanges() 

所有其他的东西都很简单。

简单的解决方案

// Simple 'focus' Directive
import Directive, Input, ElementRef from 'angular2/core';
@Directive(
    selector: '[focus]'
)
class FocusDirective 
    @Input()
    focus:boolean;
    constructor(@Inject(ElementRef) private element: ElementRef) 
    protected ngOnChanges() 
        this.element.nativeElement.focus();
    


// Usage
@Component(
    selector : 'app',
    template : `
        <input [focus]="inputFocused" type="text">
        <button (click)="moveFocus()">Move Focus</button>
    `,
    directives: [FocusDirective]
)
export class App 
    private inputFocused = false;
    moveFocus() 
        this.inputFocused = true;
        // we need this because nothing will 
        // happens on next method call, 
        // ngOnChanges in directive is only called if value is changed,
        // so we have to reset this value in async way,
        // this is ugly but works
        setTimeout(() => this.inputFocused = false);
    

EventEmitter 的解决方案

为了解决 setTimeout(() => this.inputFocused = false); 的问题,我们可以将我们的指令绑定到事件源 - EventEmitter 或 Observable。下面是 EventEmitter 的使用示例。

// Directive
import Directive, EventEmitter, Input, ElementRef from 'angular2/core';

@Directive(
    selector: '[focus]'
)
class FocusDirective 
    private focusEmitterSubscription;   
    // Now we expect EventEmitter as binded value
    @Input('focus')
    set focus(focusEmitter: EventEmitter) 
        if(this.focusEmitterSubscription) 
            this.focusEmitterSubscription.unsubscribe();
        
        this.focusEmitterSubscription = focusEmitter.subscribe(
            (()=> this.element.nativeElement.focus()).bind(this))
        
    constructor(@Inject(ElementRef) private element: ElementRef) 


// Usage
@Component(
    selector : 'app',
    template : `
        <input [focus]="inputFocused" type="text">
        <button (click)="moveFocus()">Move Focus</button>
    `,
    directives: [FocusDirective]
)
class App 
    private inputFocused = new EventEmitter();
    moveFocus() 
        this.inputFocused.emit(null);    
    

两种解决方案都可以解决您的问题,但第二种解决方案的性能要好一些,而且看起来更好。

【讨论】:

这个答案看起来与my recent answer 惊人地相似——有点太相似了,我想说。我建议你再看看我的回答。更新 2 和 3 提供了额外的实现(我更喜欢)。 对不起,马克我没有注意到你在评论中的回答。第一个解决方案与您的条目完全相同。我也喜欢您使用@ViewChild 的解决方案,但在某些情况下(例如嵌套未知组件)指令/事件发射器解决方案更灵活。取决于用例,我会看到每个解决方案的空间。 值得注意的是,任何订阅 observables 的指令都应该是一个好公民,并在 ngOnDestroy 生命周期钩子中取消订阅。【参考方案3】:

实际上您不需要为此编写任何 TS 代码(我正在使用其他答案的示例之一):

<input (keyup.enter)="focusable.focus()"/>
<input #focusable /> 

【讨论】:

【参考方案4】:

设置焦点 - Angular 2/5

<input type="text" [(ngModel)]="term2" #inputBox>

import  Component, ViewChild, ElementRef  from '@angular/core';

@Component(
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
)
export class GeneralComponent 

  @ViewChild("inputBox") _el: ElementRef;

  setFocus() 
    this._el.nativeElement.focus();
  

用于设置负载重点

ngAfterViewInit() 
    this._el.nativeElement.focus();
  

您可以为按键相应地更新此逻辑。

More Info

【讨论】:

以上是关于如何将焦点设置到另一个输入?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UIToolbar 完成按钮中将焦点从一个 UIButton 设置到另一个 UIButton

在 Windows 中使用 Java 将焦点设置到非 Java 应用程序

是否有可能强制Ios浏览器从输入焦点到另一个元素?

如何设置网页的默认输入焦点?

如何将焦点设置到独立于 id 的 HTML 表单中的第一个输入元素?

将焦点从一个组件转移到另一个组件