使用 HostListener 按 ArrowDown 和 ArrowUp 时焦点不起作用

时间:2021-01-03 23:45:06

标签: angular keyboard-events arrows

我正在寻找一种使用 ArrowUp 和 ArrowDown 键聚焦/突出显示每个 div 元素的方法。当 div 元素中的 tabindex 为 0 时,下拉列表中的第一个值会获得突出显示的边框,但仍未被选中,并且不确定如何使用 tabIndex 使用箭头向下和向上箭头遍历所有值。我有以下带有 html 文件的组件。任何帮助将不胜感激。

HTML

<div class="input">
<input type="text" #input [value]="value" >
  <div *ngIf="values">
    <div *ngFor="let value of values; let i = index">
      <div #item tabindex="i">{{value}}</div>
    </div>
  </div>

TS

  @HostListener('window:keydown', ['$event']) keyEvent(event: KeyboardEvent) {
  if (event.key == 'ArrowDown') {
    this.item.nativeElement.focus();
  } else if (event.key == 'ArrowUp') {
     this.item.nativeElement.focus();
  } else {
    //update
  }
}

1 个答案:

答案 0 :(得分:0)

this SO中你有一个方法,在这个another SO中可以作为“灵感”

好吧,使用最后一个。这个想法是有一个指令,其中包含三个变量 prev、self 和 next

@Directive({
  selector: "[next-tab]"
})
export class NextTabDirective {
  self: any;
  next: any;
  prev: any;

  @HostListener("keydown.arrowup", ["$event"])
  onUp(event: KeyboardEvent) {
    if (this.prev && this.prev.focus) {
      this.prev.focus();
      this.prev.select();
      event.preventDefault();
      return false;
    }
  }

  @HostListener("keydown.arrowdown", ["$event"])
  onDown(event: KeyboardEvent) {
    if (this.next && this.next.focus) {
      this.next.focus();
      this.next.select();
      event.preventDefault();
      return false;
    }
  }

  constructor(private control: ElementRef) {
    this.self = control.nativeElement;
  }
}

好吧,我们将创建一个新指令来考虑内部的“next-tab”

export class ManageArrowDirective implements AfterViewInit {
  @ContentChildren(NextTabDirective) controls: QueryList<NextTabDirective>;

  ngAfterViewInit() {
    const controls=this.controls.toArray()
    controls.forEach((x, index) => {
      x.prev = index ? controls[index - 1].self : null;
      x.next =
        index < controls.length - 1 ? controls[index + 1].self : null;
    });
    this.controls.changes.subscribe(ctrls => {
      const controls=ctrls.toArray();
      controls.forEach((x, index) => {
        x.prev = index ? controls[index - 1].self : null;
        x.next =
          index < controls.length - 1 ? controls[index + 1].self : null;
      });
    });
  }
}

你使用

<div mannage-arrow>
   <input next-tab ...>
   <input next-tab ...>
</div>

指令“NextTabDirective”可以应用于ngControls,因此我们可以控制它是否被禁用

我们开始!

首先在我们指令的构造函数中注入 ngControl 作为 public

  constructor(private control: ElementRef,@Optional()public ngControl:NgControl) {
    this.self = control.nativeElement;
  }

然后,实现一些复杂的指令来获取可以禁用的控件

export class ManageControlDirective implements AfterViewInit {
  @ContentChildren(NgControlDirective,{descendants:true}) controls: QueryList<NgControlDirective>;

  ngAfterViewInit() {
    this.rearrange();
    this.controls.changes.subscribe(ctrls => {
      this.rearrange(ctrls.toArray())
    });
  }
  rearrange(controls:NgControlDirective[]=null)
  {
    setTimeout(()=>{
    controls=controls||this.controls.toArray()
      controls.forEach((x, index) => {
        x.prev = this.getPrevControlEnabled(index,controls)
        x.next = this.getNextControlEnabled(index,controls)
      });

    })

  }
  getPrevControlEnabled(index,controls:NgControlDirective[]){
    if (index)
        return controls[index-1].ngControl.enabled?controls[index-1].self:this.getPrevControlEnabled(index-1,controls)
    return null;
  }
  getNextControlEnabled(index,controls:NgControlDirective[]){
    if (index<controls.length-1)
        return controls[index+1].ngControl.enabled?controls[index+1].self:this.getNextControlEnabled(index+1,controls)
    return null;
  }
}

查看 this stackbliz

中两个示例的示例