You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过双击Tab键关闭Mat Calendar?Tab事件失效问题求助

解决Mat Calendar Tab键无法关闭及事件失效问题

问题描述

按下Tab键会打开Mat Calendar,但再次按Tab键时无法关闭它。日历打开后Tab方法或事件便会失效,除非按下Esc键。

截图

日历界面截图

当前代码

HTML代码

<div fxLayout="row" style="max-width: 100px;">
  <input 
    [readonly]="true" 
    (click)="openPicker(pickerTargetDate);" 
    [(ngModel)]="data.targetDate" 
    appFocusOnLoad
    (focus)="pickerTargetDate.open()" 
    (keydown.Tab)="onEditTableInputsKeydownTab(i, 'actualProjectedDate')" 
    matInput
    [matDatepicker]="pickerTargetDate"
    (dateChange)="dateChange(data,'parent','targetDate')" 
  >
  <mat-datepicker #pickerTargetDate></mat-datepicker>
  <span *ngIf="data.targetDate && data.isRequired" (click)="openPicker(pickerTargetDate);"
    style="font-size: 20px;padding-top: 4px;margin-right:5px;">
    calendar_today
  </span>
</div>

TypeScript代码

onEditKeydownTab(index, columnName: string) {
  this.editTable(index, columnName)
}

editTable(index:number,columnName: string) {
  this.indexEditing=index;
  this.selectedCell = columnName;
}

解决方案

核心思路

Mat Datepicker打开后会接管焦点管理,默认Tab行为会在日历内部元素间循环,无法触发输入框的Tab事件。我们需要手动拦截Tab事件,根据日历状态决定打开/关闭,并处理焦点转移。

修改后的代码实现

HTML部分

<div fxLayout="row" style="max-width: 100px;">
  <input 
    [readonly]="true" 
    (click)="openPicker(pickerTargetDate)" 
    [(ngModel)]="data.targetDate" 
    appFocusOnLoad
    (focus)="pickerTargetDate.open()" 
    (keydown.Tab)="handleTabInteraction($event, pickerTargetDate, i, 'actualProjectedDate')" 
    matInput
    [matDatepicker]="pickerTargetDate"
    (dateChange)="dateChange(data,'parent','targetDate')" 
  >
  <mat-datepicker #pickerTargetDate></mat-datepicker>
  <span *ngIf="data.targetDate && data.isRequired" (click)="openPicker(pickerTargetDate)"
    style="font-size: 20px;padding-top: 4px;margin-right:5px;">
    calendar_today
  </span>
</div>

TypeScript部分

handleTabInteraction(event: KeyboardEvent, picker: any, index: number, columnName: string) {
  // 阻止默认Tab行为,避免日历内部焦点循环
  event.preventDefault();

  if (picker.opened) {
    // 关闭日历
    picker.close();
    // 执行原有Tab逻辑,切换到目标单元格
    this.editTable(index, columnName);
    // 可选:若需要将焦点直接移到下一个元素,可添加如下逻辑
    // const nextElement = event.target?.nextElementSibling;
    // if (nextElement) (nextElement as HTMLElement).focus();
  } else {
    // 打开日历
    picker.open();
  }
}

onEditKeydownTab(index: number, columnName: string) {
  this.editTable(index, columnName);
}

editTable(index: number, columnName: string) {
  this.indexEditing = index;
  this.selectedCell = columnName;
}

关键说明

  1. 拦截默认行为:通过event.preventDefault()阻止Tab键的默认焦点切换,避免日历内部的元素获取焦点。
  2. 状态判断:直接通过日历实例的opened属性判断当前状态,执行打开或关闭操作。
  3. 焦点转移:关闭日历后调用原有editTable逻辑,确保Tab键能正常切换到目标编辑单元格,也可根据需求手动指定下一个焦点元素。

内容的提问来源于stack exchange,提问作者Mark Latin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:15:36