Вопрос или проблема
Ссылки: https://material.angular.io/cdk/menu/examples
В меню Angular cdk оно закрывается при клике на любой элемент меню, но требуется, чтобы при клике на элемент меню оно открывалось и закрывалось при клике вне меню или на Esc.
Примечание – нельзя использовать https://material.angular.io/cdk/overlay/overview, так как это не обеспечивает доступность. Если мы используем эти стрелочные клавиши вверх или вниз, основное окно прокручивается, в то время как мы должны перемещаться к открытому элементу меню, и другие требования также не выполняются с помощью этого.
Код –
import {Component} from '@angular/core';
import {CdkMenu, CdkMenuItem, CdkMenuTrigger} from '@angular/cdk/menu';
/** @title Меню с отдельным триггером. */
@Component({
selector: 'cdk-menu-standalone-menu-example',
styleUrl: 'cdk-menu-standalone-menu-example.css',
templateUrl: 'cdk-menu-standalone-menu-example.html',
standalone: true,
imports: [CdkMenuTrigger, CdkMenu, CdkMenuItem],
})
export class CdkMenuStandaloneMenuExample {}
.example-menu {
display: inline-flex;
flex-direction: column;
min-width: 180px;
max-width: 280px;
background-color: rgba(255, 255, 255);
padding: 6px 0;
}
.example-menu-item,
.example-standalone-trigger {
background-color: transparent;
cursor: pointer;
border: none;
user-select: none;
min-width: 64px;
line-height: 36px;
padding: 0 16px;
display: flex;
align-items: center;
flex-direction: row;
flex: 1;
}
.example-menu-item:hover {
background-color: rgb(208, 208, 208);
}
.example-menu-item:active {
background-color: rgb(170, 170, 170);
}
.example-standalone-item {
background-color: rgb(239, 239, 239);
}
.example-standalone-item:hover {
background-color: rgb(208, 208, 208);
}
.example-standalone-item[aria-expanded='true'] {
background-color: rgb(208, 208, 208);
}
<button [cdkMenuTriggerFor]="menu" class="example-standalone-trigger">Нажми на меня!</button>
<ng-template #menu>
<div class="example-menu" cdkMenu>
<button class="example-menu-item" cdkMenuItem>Обновить</button>
<button class="example-menu-item" cdkMenuItem>Настройки</button>
<button class="example-menu-item" cdkMenuItem>Помощь</button>
<button class="example-menu-item" cdkMenuItem>Выйти</button>
</div>
</ng-template>
Ответ или решение
Для решения вашей задачи, где меню должно оставаться открытым при клике на элемент, но закрываться при клике вне меню или на клавишу Escape, нам нужно немного изменить текущую реализацию с использованием Angular CDK. Я предоставлю вам актуализированный код, который реализует данное поведение, без использования cdk/overlay
.
Шаги для реализации:
- Обработка клика на элементе меню: При клике на элемент меню, нужно предотвратить закрытие.
- Закрытие меню по клику вне его: Используйте
HostListener
для отслеживания кликов вне области меню. - Обработка клавиши Escape: Слушайте события клавиатуры, чтобы закрывать меню при нажатии клавиши Escape.
Полный код:
TypeScript (component.ts):
import { Component, HostListener, ViewChild } from '@angular/core';
import { CdkMenuTrigger } from '@angular/cdk/menu';
@Component({
selector: 'cdk-menu-standalone-menu-example',
styleUrls: ['cdk-menu-standalone-menu-example.css'],
templateUrl: 'cdk-menu-standalone-menu-example.html',
})
export class CdkMenuStandaloneMenuExample {
@ViewChild(CdkMenuTrigger) trigger!: CdkMenuTrigger;
toggleMenu(event: MouseEvent): void {
event.stopPropagation();
this.trigger.toggleMenu();
}
@HostListener('document:click', ['$event'])
closeMenu(event: MouseEvent): void {
if (this.trigger.menuOpen) {
this.trigger.closeMenu();
}
}
@HostListener('document:keydown.escape', ['$event'])
handleKeyboardEvent(event: KeyboardEvent): void {
if (this.trigger.menuOpen) {
this.trigger.closeMenu();
}
}
}
HTML (component.html):
<button (click)="toggleMenu($event)" class="example-standalone-trigger">Click me!</button>
<ng-template #menu>
<div class="example-menu" cdkMenu>
<button class="example-menu-item" cdkMenuItem (click)="toggleMenu($event)">Refresh</button>
<button class="example-menu-item" cdkMenuItem (click)="toggleMenu($event)">Settings</button>
<button class="example-menu-item" cdkMenuItem (click)="toggleMenu($event)">Help</button>
<button class="example-menu-item" cdkMenuItem (click)="toggleMenu($event)">Sign out</button>
</div>
</ng-template>
CSS (component.css):
.example-menu {
display: inline-flex;
flex-direction: column;
min-width: 180px;
max-width: 280px;
background-color: rgba(255, 255, 255);
padding: 6px 0;
}
.example-menu-item,
.example-standalone-trigger {
background-color: transparent;
cursor: pointer;
border: none;
user-select: none;
min-width: 64px;
line-height: 36px;
padding: 0 16px;
display: flex;
align-items: center;
flex-direction: row;
flex: 1;
}
.example-menu-item:hover {
background-color: rgb(208, 208, 208);
}
.example-menu-item:active {
background-color: rgb(170, 170, 170);
}
Объяснение изменений:
-
toggleMenu
метод: Этот метод предотвращает закрытие меню при клике на элементы. МетодtoggleMenu
используется для показа и скрытия меню. -
HostListener
для клика и клавиатуры:@HostListener('document:click')
следит за кликами вне меню, и закрывает его, если оно открыто.@HostListener('document:keydown.escape')
проверяет нажатие клавиши Escape и закрывает меню, если оно открыто.
С помощью этих изменений, вы получите меню, которое будет вести себя согласно вашим требованиям.