更新:重构了基于JSON的“任意深度嵌套”示例,因为它在Angular 12中不再起作用。这是一个基于
这篇好文章的工作中的Angular 13
StackBlitz示例。
为了使其正常工作,我将菜单触发按钮移动到菜单项组件内部,以便每个菜单项组件实例中只有一个菜单。
menu-item.component.html
<mat-menu #menu="matMenu" [overlapTrigger]="false">
<span *ngFor="let child of children">
<ng-container *ngIf="child.children && child.children.length > 0">
<app-menu-item [item]="child" [children]="child.children"></app-menu-item>
</ng-container>
<ng-container *ngIf="!child.children || child.children.length === 0">
<button mat-menu-item color="primary" [routerLink]="child.route">
{{ child.displayName }}
</button>
</ng-container>
</span>
</mat-menu>
<button
mat-menu-item
color="primary"
[matMenuTriggerFor]="menu"
[disabled]="item.disabled"
>
<mat-icon>{{ item.iconName }}</mat-icon>
{{ item.displayName }}
</button>
菜单项组件.ts
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { NavItem } from '../nav-item';
@Component({
selector: 'app-menu-item',
templateUrl: './menu-item.component.html',
styleUrls: ['./menu-item.component.css'],
})
export class MenuItemComponent implements OnInit {
@Input() children: NavItem[];
@Input() item: NavItem;
constructor(public router: Router) {}
ngOnInit() {}
}
app.component.html
->
app组件的html文件
<div class="basic-container">
<mat-toolbar class="menu-bar mat-elevation-z1">
<span *ngFor="let item of navItems">
<ng-container *ngIf="item.children && item.children.length > 0">
<app-menu-item [item]="item" [children]="item.children"></app-menu-item>
</ng-container>
<ng-container *ngIf="!item.children || item.children.length === 0">
<button mat-button color="primary" [routerLink]="item.route">
{{ item.displayName }}
</button>
</ng-container>
</span>
</mat-toolbar>
<router-outlet></router-outlet>
</div>
这里是一个 StackBlitz 示例,它基于 JSON 构建了任意深度的嵌套(由 @Splaktar 撰写)
任意嵌套的关键在于自我引用的menu-item.component:
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {Router} from '@angular/router';
import {NavItem} from '../nav-item';
@Component({
selector: 'app-menu-item',
templateUrl: './menu-item.component.html',
styleUrls: ['./menu-item.component.scss']
})
export class MenuItemComponent implements OnInit {
@Input() items: NavItem[];
@ViewChild('childMenu') public childMenu;
constructor(public router: Router) {
}
ngOnInit() {
}
}
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">
<span *ngFor="let child of items">
<span *ngIf="child.children && child.children.length > 0">
<button mat-menu-item color="primary" [matMenuTriggerFor]="menu.childMenu">
<mat-icon>{{child.iconName}}</mat-icon>
<span>{{child.displayName}}</span>
</button>
<app-menu-item #menu [items]="child.children"></app-menu-item>
</span>
<span *ngIf="!child.children || child.children.length === 0">
<button mat-menu-item [routerLink]="child.route">
<mat-icon>{{child.iconName}}</mat-icon>
<span>{{child.displayName}}</span>
</button>
</span>
</span>
</mat-menu>