代码之家  ›  专栏  ›  技术社区  ›  Marshal

中心Mat菜单,中心MatMenu覆盖到按钮

  •  0
  • Marshal  · 技术社区  · 6 年前

    Material Issue 9631 居中 mat-menu 按钮如下。

    问题是,支持它会偏离规范,最终看起来很奇怪。


    我需要这个功能。。。因为我写的时间比我的CDK要多 组件。。。我对重新创建 ,只需要菜单居中。。。我也不感兴趣的任何其他图书馆完成这一点,我想使用材料 ,所以我的问题如下。

    问题:

    利用角 directive MatMenuTrigger 将CDK覆盖置于按钮中心?

    enter image description here

    1 回复  |  直到 6 年前
        1
  •  3
  •   Marshal    6 年前

    我选择指令是因为 MatMenuTrigger Directive ,复制材料来源使用的逻辑是有意义的。

    到目前为止,这是我提出的方法,我不确定这样进入课堂本身是否“可以接受”,或者这样做是否有任何负面影响。

    我愿意就这种方法进行建设性的讨论,以提出任何建议或改进。


    斯塔克闪电战

    https://stackblitz.com/edit/angular-jpgjdc-nqmyht?embed=1&file=app/center-matmenu.directive.ts

    基本上我是在分离 matMenuTrigger 把它放在 div 包装 mat-menu

    • 我也在分配 menuTrigger 到a templateRef 并将其作为输入传递给我的 center-mat-menu 选择器
    <button mat-button [center-mat-menu]="menuTrigger">Menu</button>
    <div #menuTrigger="matMenuTrigger" [matMenuTriggerFor]="menu">
     <mat-menu #menu="matMenu">
    

    从那里我创建了一个听众通过 @HostListener

    @HostListener('click', ['$event'])
    

    然后复制 马特纽特里格 指令来操纵位置、初始化菜单并在单击时激发打开的动画。

    这基本上是 openMenu() 方法 menu-trigger.ts source,除非我在初始化菜单后和调用之前操作左和上样式 this.menuTrigger.menu['_startAnimation'](); 打开菜单。

    menu-trigger.ts

    我将源按钮的维度存储到变量和 要计算的初始化菜单的宽度 left

    @Directive({
      selector: '[center-mat-menu]'
    })
    export class CenterMatmenuDirective {
      overlayRef: OverlayRef;
      overlayConf: OverlayConfig;
      dropDown: HTMLElement;
      overlayPositionBox: HTMLElement;
      menu: MatMenuPanel;
      button: HTMLElement;
      buttonWidth: number;
      buttonLeft: number;
      buttonBottom: number;
    
      @Input('center-mat-menu') private menuTrigger: MatMenuTrigger;
    
      constructor(private _menuButton: ElementRef, private _renderer: Renderer2) { }
    
      @HostListener('click', ['$event'])
      onclick(e) {
        this._setVariables();
        //menu not opened by keyboard down arrow, have to set this so MatMenuTrigger knows the menu was opened with a mouse click
        this.menuTrigger['_openedBy'] = e.button === 0 ? 'mouse' : null;
    
        this._overrideMatMenu();
    
        this.dropDown = this.overlayRef.overlayElement.children[0].children[0] as HTMLElement;
        this.overlayPositionBox = this.overlayRef.hostElement;
    
        setTimeout(() => {
          this._styleDropDown(this.dropDown);
          this._setOverlayPosition(this.dropDown, this.overlayPositionBox);
          this._openMenu();
        })
      }
    
      private _setVariables() {
        const config = this.menuTrigger['_getOverlayConfig']();
        this.menuTrigger['_overlayRef'] = this.menuTrigger['_overlay'].create(config);
        this.overlayRef = this.menuTrigger['_overlayRef'];
        this.overlayConf = this.overlayRef.getConfig();
        this.overlayRef.keydownEvents().subscribe();
        this.menu = this.menuTrigger.menu;
        this._setButtonVars();
      }
    
      private _setButtonVars() {
        this.button = this._menuButton.nativeElement;
        this.buttonWidth = this.button.getBoundingClientRect().width;
        this.buttonLeft = this.button.getBoundingClientRect().left;
        this.buttonBottom = this.button.getBoundingClientRect().bottom;
      }
    
      private _overrideMatMenu() {
        let strat = this.overlayConf.positionStrategy as FlexibleConnectedPositionStrategy;
        this.menuTrigger['_setPosition'](strat);
        strat.positionChanges.subscribe(() => {
          this._setButtonVars();
          this._setOverlayPosition(this.dropDown, this.overlayPositionBox);
        })
        this.overlayConf.hasBackdrop = this.menu.hasBackdrop == null ?
          !this.menuTrigger.triggersSubmenu() : this.menu.hasBackdrop;
        this.overlayRef.attach(this.menuTrigger['_getPortal']());
    
        if (this.menu.lazyContent) {
          this.menu.lazyContent.attach()
        }
    
        this.menuTrigger['_closeSubscription'] = this.menuTrigger['_menuClosingActions']().subscribe(() => {
          this.menuTrigger.closeMenu();
        });
        this.menuTrigger['_initMenu']();
      }
    
      private _styleDropDown(dropDown: HTMLElement) {
        this._renderer.setStyle(this._renderer.parentNode(dropDown), 'transform-origin', 'center top 0px');
      }
    
      private _setOverlayPosition(dropDown: HTMLElement, overlayPositionBox: HTMLElement) {
        let dropDownleft = ((this.buttonWidth / 2 + this.buttonLeft) - dropDown.offsetWidth / 2);
    
        this._renderer.setStyle(overlayPositionBox, 'top', this.buttonBottom + 5 + 'px');
        this._renderer.setStyle(overlayPositionBox, 'left', dropDownleft + 'px');
        this._renderer.setStyle(overlayPositionBox, 'height', '100%');
      }
    
      private _openMenu() {
        this.menuTrigger.menu['_startAnimation']();
      }
    }