如何在 keyCode 导航的输入中设置自动焦点?
How can I set an automatic focus in the input for a keyCode navigation?
我写了一个table,里面都包含输入字段。对于这个模板,我开发了一个 keyCode 导航。可以进行上、下、左、右导航。我必须在我的代码中添加什么才能使光标直接聚焦在导航时?
我的代码:
// Snippet from HTML
...
<tbody formArrayName="rows">
<tr *ngFor="let rowControl of rows.controls; let rowIndex = index">
<td [formGroupName]="rowIndex" appArrowKeyNav *ngFor="let column of displayedColumns; let columnIndex = index;">
<div>
<span>
<label>
<input [formControl]="rowControl.get(column.attribute)">
</label>
</span>
</div>
</td>
</tr>
</tbody>
// TS
public move(object: any) {
const inputToArray = this.inputs.toArray();
const cols = this.displayedColumns.length;
let index = inputToArray.findIndex((x) => x.element === object.element);
// console.log('Index found:', index);
switch (object.action) {
case 'UP':
index -= cols;
break;
case 'DOWN':
index += cols;
break;
case 'LEFT':
index -= 1;
break;
case 'RIGHT':
index += 1;
break;
}
if (index >= 0 && index < this.inputs.length) {
console.log('Navigating to index:', index);
inputToArray[index].element.nativeElement.focus();
}
}
// Directive
@HostListener('keydown', ['$event']) onKeyUp(event: KeyboardEvent) {
switch (event.key) {
case 'ArrowUp':
this.keyboardService.sendMessage({ element: this.element, action: 'UP' });
break;
case 'ArrowLeft':
this.keyboardService.sendMessage({ element: this.element, action: 'LEFT' });
break;
case 'ArrowDown':
this.keyboardService.sendMessage({ element: this.element, action: 'DOWN' });
break;
case 'ArrowRight':
this.keyboardService.sendMessage({ element: this.element, action: 'RIGHT' });
break;
case 'Enter':
this.keyboardService.sendMessage({ element: this.element, action: 'ENTER' });
break;
}
}
这是 myStackblitz:https://stackblitz.com/edit/angular-wmfjhh-zfkyyx?file=app%2Ftable-basic-example.html
一种可能的方法是让 table 的单元格可以使用箭头键进行导航
使用 id
属性使用 *ngFor
索引存储行和列信息
<tr *ngFor="let rowControl of rows.controls; let i = index">
<ng-container [formGroupName]="i">
<td>
<input [id]="'row-' + i + '-col-0'" formControlName="name" (focus)="onFocus($event)">
</td>
<td>
<input [id]="'row-' + i + '-col-1'" formControlName="age" (focus)="onFocus($event)">
</td>
<td>
<input [id]="'row-' + i + '-col-2'" formControlName="color" (focus)="onFocus($event)">
</td>
</ng-container>
</tr>
在这种情况下,第一行的 ID 将是 row-0-col-0
、row-0-col-1
等。
第二行 row-1-col-0
还有一个 onFocus
事件处理程序,它会将当前单元格设置为焦点
一旦keyUp
被触发
@HostListener('keydown', ['$event'])
onKeyUp(event: KeyboardEvent) {
console.log(event.key);
if (this.currentInputInFocus) {
const id = this.currentInputInFocus.id;
if (id && id.includes('row-')) {
const arr = id.split('-');
let row: number = Number(arr[1]);
let col: number = Number(arr[3]);
switch (event.key) {
case 'ArrowUp':
--row;
break;
case 'ArrowLeft':
--col;
break;
case 'ArrowDown':
++row;
break;
case 'ArrowRight':
++col;
break;
case 'Enter':
// do nothing
break;
}
this.setFocus(row, col);
}
}
}
获取当前聚焦的元素id,例如。 'row-0-col-0' 并根据按键更改行或列值,然后尝试聚焦新元素
private setFocus(row: number, col: number) {
const newElementToFocusOn = document.getElementById(`row-${row}-col-${col}`);
if (newElementToFocusOn) {
this.currentInputInFocus = newElementToFocusOn;
this.currentInputInFocus.focus();
}
}
在 ngAfterViewInit
中最初聚焦的单元格可以设置为:
ngAfterViewInit() {
const row = 1;
const col = 0;
this.setFocus(row, col);
}
更新
要将您的 Stackblitz 用作上下文,只需很少的 mod 即可使其工作:
- 设置正确的 id 属性
[id]="'row-' + rowIndex + '-col-' + columnIndex"
- 跟踪当前聚焦的输入:
currentInputInFocus!: HTMLElement;
- 其余与原demo相同
Forked and updated your Stackblitz
第二次更新
The HTMLElement.focus() method sets focus on the specified element, if
it can be focused.
一种解决方法是根据此 answer
添加 tabindex="0"
属性
返回演示。正如@Aviad P. 提到的 ng-template
上的指令不起作用。相反:
<ng-template #otherColumns>
<div tabindex="0" [id]="'row-' + rowIndex + '-col-' + columnIndex" arrow-div>
Here is a Number
</div>
</ng-template>
第三次更新
要继续导航,您可以在 case 'RIGTH':
上试试这个
++col; // try to move to next column
if (col >= this.columns.length) { // check if moved past last column
col = 0; // go to column at zero index (1st column)
++row; // go to next row
}
你有一个错误(好吧,至少有一个),你已经将你的 arrow-div
附加到你的 <ng-template>
这导致类型 Comment
的节点被添加到你的 inputs
QueryList
- 这些节点没有 focus()
函数,因此您的代码失败。
这是问题区域:
<ng-template arrow-div #otherColumns>
Here is a Number
</ng-template>
除此之外,当您按下键盘箭头时,您的索引会在错误的间隙中跳跃,但是一旦您修复了之前的错误,它就会毫无错误地跳跃。
我写了一个table,里面都包含输入字段。对于这个模板,我开发了一个 keyCode 导航。可以进行上、下、左、右导航。我必须在我的代码中添加什么才能使光标直接聚焦在导航时?
我的代码:
// Snippet from HTML
...
<tbody formArrayName="rows">
<tr *ngFor="let rowControl of rows.controls; let rowIndex = index">
<td [formGroupName]="rowIndex" appArrowKeyNav *ngFor="let column of displayedColumns; let columnIndex = index;">
<div>
<span>
<label>
<input [formControl]="rowControl.get(column.attribute)">
</label>
</span>
</div>
</td>
</tr>
</tbody>
// TS
public move(object: any) {
const inputToArray = this.inputs.toArray();
const cols = this.displayedColumns.length;
let index = inputToArray.findIndex((x) => x.element === object.element);
// console.log('Index found:', index);
switch (object.action) {
case 'UP':
index -= cols;
break;
case 'DOWN':
index += cols;
break;
case 'LEFT':
index -= 1;
break;
case 'RIGHT':
index += 1;
break;
}
if (index >= 0 && index < this.inputs.length) {
console.log('Navigating to index:', index);
inputToArray[index].element.nativeElement.focus();
}
}
// Directive
@HostListener('keydown', ['$event']) onKeyUp(event: KeyboardEvent) {
switch (event.key) {
case 'ArrowUp':
this.keyboardService.sendMessage({ element: this.element, action: 'UP' });
break;
case 'ArrowLeft':
this.keyboardService.sendMessage({ element: this.element, action: 'LEFT' });
break;
case 'ArrowDown':
this.keyboardService.sendMessage({ element: this.element, action: 'DOWN' });
break;
case 'ArrowRight':
this.keyboardService.sendMessage({ element: this.element, action: 'RIGHT' });
break;
case 'Enter':
this.keyboardService.sendMessage({ element: this.element, action: 'ENTER' });
break;
}
}
这是 myStackblitz:https://stackblitz.com/edit/angular-wmfjhh-zfkyyx?file=app%2Ftable-basic-example.html
一种可能的方法是让 table 的单元格可以使用箭头键进行导航
使用 id
属性使用 *ngFor
索引存储行和列信息
<tr *ngFor="let rowControl of rows.controls; let i = index">
<ng-container [formGroupName]="i">
<td>
<input [id]="'row-' + i + '-col-0'" formControlName="name" (focus)="onFocus($event)">
</td>
<td>
<input [id]="'row-' + i + '-col-1'" formControlName="age" (focus)="onFocus($event)">
</td>
<td>
<input [id]="'row-' + i + '-col-2'" formControlName="color" (focus)="onFocus($event)">
</td>
</ng-container>
</tr>
在这种情况下,第一行的 ID 将是 row-0-col-0
、row-0-col-1
等。
第二行 row-1-col-0
还有一个 onFocus
事件处理程序,它会将当前单元格设置为焦点
一旦keyUp
被触发
@HostListener('keydown', ['$event'])
onKeyUp(event: KeyboardEvent) {
console.log(event.key);
if (this.currentInputInFocus) {
const id = this.currentInputInFocus.id;
if (id && id.includes('row-')) {
const arr = id.split('-');
let row: number = Number(arr[1]);
let col: number = Number(arr[3]);
switch (event.key) {
case 'ArrowUp':
--row;
break;
case 'ArrowLeft':
--col;
break;
case 'ArrowDown':
++row;
break;
case 'ArrowRight':
++col;
break;
case 'Enter':
// do nothing
break;
}
this.setFocus(row, col);
}
}
}
获取当前聚焦的元素id,例如。 'row-0-col-0' 并根据按键更改行或列值,然后尝试聚焦新元素
private setFocus(row: number, col: number) {
const newElementToFocusOn = document.getElementById(`row-${row}-col-${col}`);
if (newElementToFocusOn) {
this.currentInputInFocus = newElementToFocusOn;
this.currentInputInFocus.focus();
}
}
在 ngAfterViewInit
中最初聚焦的单元格可以设置为:
ngAfterViewInit() {
const row = 1;
const col = 0;
this.setFocus(row, col);
}
更新
要将您的 Stackblitz 用作上下文,只需很少的 mod 即可使其工作:
- 设置正确的 id 属性
[id]="'row-' + rowIndex + '-col-' + columnIndex"
- 跟踪当前聚焦的输入:
currentInputInFocus!: HTMLElement;
- 其余与原demo相同
Forked and updated your Stackblitz
第二次更新
The HTMLElement.focus() method sets focus on the specified element, if it can be focused.
一种解决方法是根据此 answer
添加tabindex="0"
属性
返回演示。正如@Aviad P. 提到的 ng-template
上的指令不起作用。相反:
<ng-template #otherColumns>
<div tabindex="0" [id]="'row-' + rowIndex + '-col-' + columnIndex" arrow-div>
Here is a Number
</div>
</ng-template>
第三次更新
要继续导航,您可以在 case 'RIGTH':
++col; // try to move to next column
if (col >= this.columns.length) { // check if moved past last column
col = 0; // go to column at zero index (1st column)
++row; // go to next row
}
你有一个错误(好吧,至少有一个),你已经将你的 arrow-div
附加到你的 <ng-template>
这导致类型 Comment
的节点被添加到你的 inputs
QueryList
- 这些节点没有 focus()
函数,因此您的代码失败。
这是问题区域:
<ng-template arrow-div #otherColumns>
Here is a Number
</ng-template>
除此之外,当您按下键盘箭头时,您的索引会在错误的间隙中跳跃,但是一旦您修复了之前的错误,它就会毫无错误地跳跃。