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

mat-autocomplete结合cdk-virtual-scroll-viewport箭头键导航失效解决方案咨询

解决Mat-Autocomplete结合CDK虚拟滚动时的箭头键导航问题

问题原因

Mat-Autocomplete的默认键盘导航逻辑会直接查找<mat-option>作为直接子元素,但你用<cdk-virtual-scroll-viewport>把选项包裹起来后,组件无法识别嵌套的选项,导致箭头键导航失效。

手动实现键盘导航方案

你可以通过监听键盘事件,结合CDK虚拟滚动API和焦点管理来实现自定义导航:

1. 模板调整:添加必要引用

<mat-autocomplete 
  autoActiveFirstOption 
  #auto="matAutocomplete" 
  (opened)="isOpen = true; doOpen()" 
  (closed)="isOpen = false; save()"
  (keydown)="handleKeydown($event)"
>
  <ng-container *ngIf="!disabled">
    <cdk-virtual-scroll-viewport #scrollViewport [ngStyle]="{ height: height }" itemSize="25">
      <mat-option 
        *cdkVirtualFor="let item of filteredItems; let i = index" 
        [value]="item.text"
        #options="matOption"
      >
        {{ item.text }}
      </mat-option>
    </cdk-virtual-scroll-viewport>
  </ng-container>
</mat-autocomplete>

2. 组件类实现导航逻辑

在组件的.ts文件中添加以下代码:

import { Component, ViewChild, QueryList } from '@angular/core';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { MatOption } from '@angular/material/core';
import { MatAutocomplete } from '@angular/material/autocomplete';

@Component({
  // 你的组件元数据
})
export class YourComponent {
  @ViewChild('scrollViewport') scrollViewport!: CdkVirtualScrollViewport;
  @ViewChild('auto') autocomplete!: MatAutocomplete;
  @ViewChildren('options') options!: QueryList<MatOption>;
  
  selectedIndex = 0;
  filteredItems: any[] = []; // 你的数据源

  handleKeydown(event: KeyboardEvent) {
    if (event.key === 'ArrowDown') {
      event.preventDefault();
      this.selectedIndex = Math.min(this.selectedIndex + 1, this.filteredItems.length - 1);
      this.updateActiveOption();
    } else if (event.key === 'ArrowUp') {
      event.preventDefault();
      this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
      this.updateActiveOption();
    } else if (event.key === 'Enter') {
      event.preventDefault();
      const targetOption = this.options.find((_, idx) => idx === this.selectedIndex);
      targetOption && this.autocomplete.selectOption(targetOption);
    }
  }

  updateActiveOption() {
    // 滚动到选中项位置
    this.scrollViewport.scrollToIndex(this.selectedIndex);
    // 更新选项激活状态
    this.options.forEach((opt, idx) => {
      opt._setActive(idx === this.selectedIndex);
    });
  }

  doOpen() {
    // 打开时重置选中索引
    this.selectedIndex = 0;
    this.updateActiveOption();
  }
}

其他大数据Autocomplete替代方案

如果不想手动实现导航逻辑,可以考虑以下成熟方案:

  • PrimeNG AutoComplete:原生支持虚拟滚动(通过[virtualScroll]="true"开启),内置完整的键盘导航功能,无需额外配置。
  • ng-select:开启虚拟滚动模式后,自动支持键盘导航,同时提供丰富的自定义配置项适配不同场景。
  • 自定义虚拟滚动下拉:基于Angular CDK的虚拟滚动和焦点管理器,完全自定义下拉逻辑,自由度更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 23:28:26