角度:我想将div的焦点从箭头键按钮移到另一个

时间:2019-06-15 08:00:19

标签: javascript angular typescript

我正在做角度项目,遇到这样的情况:我连续有一系列的div,当用户单击任何一个div时,他应该能够使用箭头键从一个div移到另一个div。

请帮助。

我尝试使用按键事件,但并没有帮助我。试图找出关于stackoverflow的类似问题,但所有答案都在jquery中,我需要在打字稿中输入。

moveCell(e){
  console.log(e);
}
.container{
width: 100%;
}

.cell{
width: 100px;
float:left;
}

.cell:hover,
.cell:focus{
background: red;
}
<div class="container">
<div class="cell" (keypress)="moveCell($event)">cell 1</div>
  <div class="cell" (keypress)="moveCell($event)">cell 2</div>
  <div class="cell" (keypress)="moveCell($event)">cell 3</div>
  <div class="cell" (keypress)="moveCell($event)">cell 4</div>
  <div class="cell" (keypress)="moveCell($event)">cell 5</div>
  <div class="cell" (keypress)="moveCell($event)">cell 6</div>
  <div class="cell" (keypress)="moveCell($event)">cell 7</div>
  <div class="cell" (keypress)="moveCell($event)">cell 8</div>
  <div class="cell" (keypress)="moveCell($event)">cell 9</div>
</div>

在我的代码中,如果用户单击单元格2,则焦点应自动转到单元格2。此后,如果用户使用键盘并按箭头键,则应将焦点移至下一个/上一个单元格。

2 个答案:

答案 0 :(得分:2)

keypress未检测到arrow keys,而是使用keydown。为了获得焦点并聆听按键事件,请向div添加属性tabindex

对于右箭头键,您需要检查当前活动元素是否不是最后一个元素,并将焦点更改为下一个元素。

对于左箭头键,检查当前活动元素是否不是第一个元素,然后将焦点更改为上一个元素。

-HTML-

<div class="container">
  <div tabindex="0" class="cell" (keydown)="moveCell($event)">cell 2</div>
  <div tabindex="1" class="cell" (keydown)="moveCell($event)">cell 3</div>
  <div tabindex="2" class="cell" (keydown)="moveCell($event)">cell 4</div>
  <div tabindex="3" class="cell" (keydown)="moveCell($event)">cell 5</div>
  <div tabindex="4" class="cell" (keydown)="moveCell($event)">cell 6</div>
  <div tabindex="5" class="cell" (keydown)="moveCell($event)">cell 7</div>
  <div tabindex="6" class="cell" (keydown)="moveCell($event)">cell 8</div>
</div>

-组件代码-

  length: 0;
  domEles;
  moveCell(e){
    const activeEle = document.activeElement;
    const activeEleIndex = Array.prototype.indexOf.call(this.domEles, activeEle);
    if(e.key == "ArrowRight" && activeEleIndex < this.length - 1 ) {
        activeEle.nextElementSibling.focus();
    } 

    if(e.key == "ArrowLeft" && activeEleIndex > 0) {
       activeEle.previousElementSibling.focus();
    }
  }

  ngOnInit() {
    this.domEles = document.querySelectorAll('.container > *');
    this.length = this.domEles.length;
  }

Working Code-https://stackblitz.com/edit/angular-5qxicw

答案 1 :(得分:0)

还有一个使用指令的方法。好吧,我们的想法是,我们使用ViewChildren在app.component中获取所有包含指令的div,然后将带有指令的div发送一个事件并调用app.component的函数。所以app.component变成了

<div arrow-div (event)="handler($event)>my div</div>
<div arrow-div (event)="handler($event)>my div</div>
...

但是我们可以使用“服务”使事物更“透明”。

想象一下类似的服务

@Injectable({
  providedIn: 'root',
})
export class KeyBoardService {
  keyBoard:Subject<any>=new Subject<any>();
  sendMessage(message:any)
  {
    this.keyBoard.next(message)
  }
}

当按下键箭头时,我们的指令可以调用服务“ sendMessage”,并且在我们的app.component中订阅该服务。然后我们的app.component就像

<div arrow-div >my div</div>
<div arrow-div >my div</div>
<br/>
<div arrow-div >my div</div>
<div arrow-div >my div</div>

我们避免在div中使用此“ ugly”(event)=“ handler($ event)”!

好吧,该指令很简单,使用@Hostlistener侦听键,并使用renderer2添加属性“ tabindex”(要使div可聚焦,我们需要添加tabIndex)。所以

@Directive({
  selector: '[arrow-div]',
})
export class ArrowDivDirective {
  constructor(private keyboardService: KeyBoardService, public element: ElementRef, private render: Renderer2) {
    this.render.setAttribute(this.element.nativeElement, "tabindex", "0")
  }


  @HostListener('keydown', ['$event']) onKeyUp(e) {

    switch (e.keyCode) {
      case 38:
        this.keyboardService.sendMessage({ element: this.element, action: 'UP' })
        break;
      case 37:
        this.keyboardService.sendMessage({ element: this.element, action: 'LEFT' })
        break;
      case 40:
        this.keyboardService.sendMessage({ element: this.element, action: 'DOWN' })
        break;
      case 39:
        this.keyboardService.sendMessage({ element: this.element, action: 'RIGTH' })
        break;
    }
  }
}

还有我们的app.component.ts

export class AppComponent implements OnInit {
  columns:number=2;
  @ViewChildren(ArrowDivDirective) inputs:QueryList<ArrowDivDirective>

  constructor(private keyboardService:KeyBoardService){}
  ngOnInit()
  {
    this.keyboardService.keyBoard.subscribe(res=>{
      this.move(res)
    })
  }
  move(object)
  {
    const inputToArray=this.inputs.toArray()
    let index=inputToArray.findIndex(x=>x.element==object.element);
    switch (object.action)
    {
      case "UP":
        index-=this.columns;
        break;
      case "DOWN":
        index+=this.columns;
        break;
      case "LEFT":
        index--;
        break;
      case "RIGTH":
        index++;
        break;
      case "RIGTH":
        index++;
        break;
    }

    if (index>=0 && index<this.inputs.length)
      inputToArray[index].element.nativeElement.focus();
  }
}

请注意,如果我们要对cols和rows创建“ grid”,并使用上下键在各行之间移动,那么我将使用变量“ column”。发送“元素”以避免我们必须存储“ div集中”

您可以在stackblitz

中查看示例