深入指南
Angular Aria

Menubar

概述

功能表列是一條水平導覽列,讓使用者能隨時取用應用程式選單。功能表列將指令組織成 File、Edit、View 等邏輯分類,協助使用者透過鍵盤或滑鼠探索並執行應用程式功能。

用法

功能表列很適合將應用程式指令組織成常駐且容易探索的導覽。

適合使用功能表列的情況:

  • 建立應用程式指令列(例如 File、Edit、View、Insert、Format)
  • 建立在整個介面中持續可見的導覽
  • 將指令組織成邏輯清晰的頂層分類
  • 需要支援鍵盤的水平選單導覽
  • 建立桌面風格的應用程式介面

避免使用功能表列的情況:

  • 為個別動作建立下拉選單(改用搭配觸發器的 Menu)
  • 建立內容選單(改用 Menu 指南模式)
  • 簡單的獨立動作清單(改用 Menu)
  • 水平空間有限的行動介面
  • 導覽應放在側邊欄或頁首導覽模式中

功能

  • 水平導覽:用左/右方向鍵在頂層分類之間移動
  • 持續可見:永遠顯示,不是強制回應視窗,也無法關閉
  • 懸停開啟:首次以鍵盤或點選互動後,子選單會在懸停時開啟
  • 巢狀子選單:支援多層選單深度
  • 鍵盤導覽:方向鍵、Enter/Space、Escape,以及搶先輸入搜尋(typeahead)
  • 停用狀態:可停用整個功能表列或個別項目
  • RTL 支援:自動支援由右至左語言的導覽

範例

基本功能表列

功能表列讓使用者能隨時取用依頂層分類組織的應用程式指令。使用者用左/右方向鍵在分類之間移動,並用 Enter 或下方向鍵開啟選單。

按下右方向鍵可在 File、Edit 與 View 之間移動。按下 Enter 或下方向鍵可開啟選單,並用上/下方向鍵導覽子選單項目。

停用功能表列項目

停用個別選單項目或整個功能表列,以防止互動。使用 softDisabled 輸入屬性控制停用項目是否能取得鍵盤焦點。

當功能表列的 [softDisabled]="true" 時,停用項目可以取得焦點,但無法啟用。當 [softDisabled]="false" 時,鍵盤導覽會跳過停用項目。

RTL 支援

功能表列會自動適應由右至左(RTL)語言。方向鍵導覽會反轉方向,子選單則定位在左側。

dir="rtl" 屬性可啟用 RTL 模式。左方向鍵改為往右移動、右方向鍵改為往左移動,讓 RTL 語言使用者能自然地導覽。

測試

Angular Aria 提供元件測試工具(component harness)來測試功能表列元件。 以下範例示範如何在元件測試中使用這些測試工具:

import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {MenuHarness} from '@angular/aria/menu/testing';
import {MyMenubarComponent} from './my-menubar'; // Your component

describe('MyMenubarComponent', () => {
  let fixture: ComponentFixture<MyMenubarComponent>;
  let loader: HarnessLoader;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [MyMenubarComponent],
    });

    fixture = TestBed.createComponent(MyMenubarComponent);
    await fixture.whenStable();
    loader = TestbedHarnessEnvironment.loader(fixture);
  });

  it('should interact with menubar items', async () => {
    // Load the menubar harness (which is a MenuHarness with selector '[ngMenuBar]')
    const menubar = await loader.getHarness(MenuHarness.with({selector: '[ngMenuBar]'}));

    // Menubars are persistent and always "open"
    expect(await menubar.isOpen()).toBe(true);
    expect(await menubar.isMenuBar()).toBe(true);

    // Get top-level items
    const items = await menubar.getItems();
    expect(items.length).toBe(2);
    expect(await items[0].getText()).toBe('File');
    expect(await items[1].getText()).toBe('Edit');

    // Click an item to open its dropdown menu
    await items[0].click();

    const fileMenu = await items[0].getSubmenu();
    expect(fileMenu).toBeTruthy();
    expect(await fileMenu!.isOpen()).toBe(true);
  });
});

API 參考

如需詳細的 API 文件,請查看下列 API 參考: