【问题标题】:Angular - How to create reusable mat menu componentAngular - 如何创建可重用的垫子菜单组件
【发布时间】:2021-06-25 04:40:52
【问题描述】:

我有垫子菜单,需要在多个地方触发。

  1. 我有重复的列表项(ngFor),在每个列表项上我们显示更多图标,点击它会显示带有 3 个选项的 mat 菜单,每个点击都会调用一个函数。

  2. 这里我有一个按钮,点击它会显示带有相同 3 个选项的 mat 菜单,每个点击都会调用与上述相同的功能。

每个点击功能都会打开一个垫子对话框,里面有一个表格。

最后我们有不同的菜单触发项但相同的 mat 菜单。

目前我已经重复了组件中的代码,这是一种不好的做法。我在两个组件中都有大量重复的代码。我想优化它那我们怎么做呢。

我可以为不同的菜单触发项创建通用组件吗? (这是否可能,因为触发 mat-menu 元素不同) 或者我可以创建服务来调用点击功能的菜单吗? 或者我可以创建接口并将实现功能放在那里并在我使用mat菜单的每个组件中实现该接口?

请建议我如何优化它。

【问题讨论】:

    标签: javascript angular oojs-ui


    【解决方案1】:

    我们可以创建一个“matmenu”组件,它可以由对象数组提供。

    想象一下你有一个类似的数组

      menu:any[]=[
        {label:"Vertebrates",children:[
          {label:"Fishes",children:[
              {label:"Baikal oilfish",action:1},
              {label:"Bala shark",action:2},
    
                ]},
          {label:"Amphibians",children:[
              {label:"Sonoran desert toad",action:3},
              {label:"Western toad",action:4},
              {label:"Arroyo toad",action:5},
              {label:"Yosemite toad",action:6},
    
          ]},
          {label:"Reptiles",action:7},
          {label:"Birds",action:8},
          {label:"Mammals",action:9}
          ]
        },
        {label:"Invertebrates",children:[
          {label:"Insects",action:10},
          {label:"Molluscs",action:11},
          {label:"Crustaceans",action:12}
          ]
        }
        ]
    

    您可以创建一个组件来创建“mat-menus”

    export class MenuComponent implements OnInit,AfterViewInit {
      @Input() title:string
      @Input() menu:any[]
      @Output() action:EventEmitter<any>=new EventEmitter<string>()
    
      //we are going to get all "mat-menu" using viewChildren
      @ViewChildren(MatMenu) matmenus:QueryList<MatMenu>
      menuItems:any[]=[]
      yet:boolean=false;
      submenus:any[]=[]
      ngOnInit(){
          this.createSubmenus(this.menu,"s0",1)
          this.reindex()
      }
      ngAfterViewInit(){
        //this avoid Angular give us errors, only when repaint the menu
        //we asign the [matMenutiggerFor]
        setTimeout(()=>{
            this.yet=true
            })
        }
        //simply call to the output
        onClick(value:any)
        {
          this.action.emit(value);
        }
        //return the "mat-menu" in the index selected
        getMenu(index:number)
        {
          return index>=0 && this.matmenus?this.matmenus.find((x,i)=>i==index):null
        }
        reindex(){
          //asign the "index" of the menu item
          this.submenus.forEach(menu=>{
            menu.forEach((x:any)=>{
              if (x.subMenu!=-1)
                x.subMenu=this.menuItems.indexOf(x.action)
            })
          })
        }
        createSubmenus(menu:any[],prefix:string,count:number){
           //add to the array menuItems the "prefix"
           this.menuItems.push(prefix)
           //add to submenu an object to create the submenu
           this.submenus.push(menu.map((x:any,index:number)=>(
             { 
               label:x.label,
               action:x.children===null || x.children===undefined?x.action:prefix+index,
               subMenu:x.children===null || x.children===undefined?-1:0
             }
           )))
           //if has children call the function for each child
           menu.forEach((x:any,index:number)=>{
              if (x.children){
                   this.createSubmenus(x.children,prefix+index,count+1)
              }
           })
        }
    }
    

    带有 .html

    <ng-container *ngIf="yet">
      <button mat-button [matMenuTriggerFor]="matmenus.first">
        <ng-content></ng-content>
      </button>
    </ng-container>
    
      <ng-container *ngFor="let menu of submenus">
        <mat-menu>
          <ng-container *ngFor="let item of menu">
          <button mat-menu-item *ngIf="item.subMenu!=-1 && yet"
          [matMenuTriggerFor]="getMenu(item.subMenu)">
               {{item.label}}
          </button>
          <button mat-menu-item *ngIf="item.subMenu==-1" (click)="onClick(item.action)">
            {{item.label}} 
            </button>
          </ng-container>
        </mat-menu>
      </ng-container>
    

    您可以在this stackblitz 中查看。看到你只需要给 menuComponent 一个数组创建一个函数:

    action(value:any)
    {
      console.log(value)
    }
    

    并作为

    <menu-component [menu]="menu" (action)="action($event)">
      Animals
    </menu-component>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-12
      • 2021-04-05
      • 2017-11-14
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 2018-08-24
      • 1970-01-01
      相关资源
      最近更新 更多