javascript Angular Materials -无法让多个项目工作

im9ewurl  于 2023-03-28  发布在  Java
关注(0)|答案(1)|浏览(100)

我使用Angular 8和Angular Materials来构建一个多级菜单。我可以通过对每个级别使用递归来让菜单工作。我递归地调用显示菜单每个级别的相同指令。
这一切都工作,菜单按预期生成。但是,菜单的行为不符合预期。我看过的例子,当你悬停在一个项目上时,嵌套的项目被打开,如果你移离一个项目,它的子项目被关闭。
例如,这是我制作的一个简单版本:
https://stackblitz.com/edit/dynamic-sidenav-multi-level-menu-tvim5b?file=app/app.component.html

问题

我的问题是,当我创建菜单时,如果我点击一个项目,子菜单就会打开。然而,除非我完全点击菜单,否则我永远无法让子菜单关闭。它的行为与上面的例子不同。

问题

我怎样才能让我的例子像上面一样,当菜单项失去焦点时关闭菜单项(子菜单项)?

信息

我没有在StackBlitz中放置我的具体示例,因为我不拥有代码,并且它需要后端服务来支持实现。
我认为我的问题是因为我递归地构建菜单项,而[matMenuTriggerFor]在下一个递归中引用菜单。

代码

sidenav-list.component.html

<mat-nav-list>
  <!-- Add the Home item -->
  <a mat-list-item routerLink="/home" (click)="onSidenavClose()"><mat-icon>home</mat-icon><span class="nav-caption">Home</span></a>
  <!-- Recurse over the app-sidenav-item -->
  <app-sidenav-item *ngFor="let item of navItems" [item]="item" [depth]="depth+1" [sidenavClose]="sidenavClose"></app-sidenav-item>
</mat-nav-list>

sidenav-item.component.html <app-sidenav-item>

<div>
    <button mat-button *ngIf="depth === 1" [matMenuTriggerFor]="menu"><mat-icon>play_arrow</mat-icon>{{item.name | titlecase}}</button>
    <button mat-menu-item *ngIf="depth > 1" [matMenuTriggerFor]="menu">{{item.name}}</button>

    <mat-menu #menu="matMenu">
        <button *ngIf="item.actions.getItems" mat-menu-item (click)="onItemSelected(item, 0)"><mat-icon>list</mat-icon>Get Items</button>
        <button *ngIf="item.actions.updateItem" mat-menu-item (click)="onItemSelected(item, 1)"><mat-icon>edit</mat-icon>Update Items</button>
        <button *ngIf="item.actions.addItem" mat-menu-item (click)="onItemSelected(item, 2)"><mat-icon>add</mat-icon>Add Item</button>

        <app-sidenav-item *ngFor="let child of item.children" [item]="child" [depth]="depth+1" [sidenavClose]="sidenavClose"></app-sidenav-item>
    </mat-menu>
</div>

屏幕打印

正如你所看到的,我可以在不同的节点上打开多个项目。我不能关闭前一个项目。此外,它只响应点击,而不是鼠标悬停。

kyks70gy

kyks70gy1#

事情是这样的,你必须对一些数据进行预处理,这意味着在你的对象中,你必须知道它是否有子对象,以启用更多的层次结构,你需要知道它来自哪个父对象,以过滤它来构建这个对象
你的html应该看起来像这样。因为你知道你可以去3 - 4级,你为这些级别生成模板,并在数据存在的时候玩数据。
MatMenu还有另一个名为matMenuTriggerData的@input,父项将使用它触发子项的数据。

<button mat-button [matMenuTriggerFor]="level1" [matMenuTriggerData]="getData(null, 1)">Animal index</button>

<mat-menu #level1="matMenu">
  <ng-template matMenuContent let-data="data">
      <ng-template ngFor let-item [ngForOf]="data">
          <button mat-menu-item *ngIf="item.children" [matMenuTriggerFor]="level2"
            [matMenuTriggerData]="getData(item, 2)">{{item.label}}</button>
          <button mat-menu-item *ngIf="!item.children">{{item.label}}</button>
        </ng-template>
  </ng-template>
</mat-menu>

<mat-menu #level2="matMenu">
  <ng-template matMenuContent let-data="data">
    <ng-template ngFor let-item [ngForOf]="data">
      <button mat-menu-item *ngIf="item.children" [matMenuTriggerFor]="level3"
        [matMenuTriggerData]="getData(item, 3)">{{item.label}}</button>
      <button mat-menu-item *ngIf="!item.children">{{item.label}}</button>
    </ng-template>
  </ng-template>
</mat-menu>

<mat-menu #level3="matMenu">
  <ng-template matMenuContent let-data="data">
    <button mat-menu-item *ngFor="let item of data">{{item.label}}</button>
  </ng-template>
</mat-menu>

请注意,最后一级没有更多触发器。
你可以为过滤后的数据写一个函数

getData(selected, requested) {
  return selected ? {
    data:
      this['level' + requested].filter(item => item.parent === selected.value)
  } : { data: this.level1 };
}

每一项都会包含valuelabelparenthasChildren不同级别的内容,可以直接用API挂接确保传入的对象有一个data属性,参见functon getData
您可以在https://stackblitz.com/edit/angular-yfslub上查看此解决方案
希望你能根据自己的需要进行修改。

相关问题