将 ng-alain 中的菜单替换成 ng-zorro-antd 的 nz-menu

首先,不得不说 @delon 是一个很不错的业务组件,它是 ng-alain 默认使用的业务组件!

但是由于 delon 的菜单组件 sidebar-nav 的样式是基于 css 控制的,所以当菜单折叠后,展示出来的子菜单,在某些情况操作下无法正常关闭,是需要通过监听鼠标的点击事件来关闭的,因此我才决定使用 nz-menu去替换它,并且同时不破坏其它功能(如:路由守卫、在 pad 下自动收缩菜单等)


一. 新建一个组件例如 sidebar-menu (目前是我将该组件建在 shared 目录下)

$ cd src/app/shared/
$ mkdir components
$ cd components
$ ng g ng-zorro-antd:menu-inline-collapsed -p app --styleext='less' --name=sidebar-menu

二. 修改 sidebar-menu.component.html

  • {{ group.text }}
  • {{ child1.text }}
  • {{ child1.text }}
    • {{ child2.text }}
    • {{ child2.text }}
      • {{ child3.text }}

写法一是写死的,只有三层
写法二在样式上存在没有缩进的问题,你可以根据菜单的深度( menu._depth ) 手动在 sidebarMenuTemplate 模板中加入缩进样式

三. 修改 sidebar-menu.component.ts

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectorRef,
  Input,
  Output,
  EventEmitter,
} from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { ReuseTabService } from '@delon/abc';
import { MenuService, SettingsService, Menu } from '@delon/theme';
import { Nav } from '@delon/abc/src/sidebar-nav/interface';

@Component({
  selector: 'app-sidebar-menu',
  templateUrl: './sidebar-menu.component.html',
})
export class SidebarMenuComponent implements OnInit, OnDestroy {
  list: Nav[] = [];
  private menuChange$: Subscription;
  private reuseChange$: Subscription;

  @Input() autoCloseUnderPad = true;

  @Output() select = new EventEmitter();

  constructor(
    private menuSrv: MenuService,
    private reuseSrv: ReuseTabService,
    public settings: SettingsService,
    private router: Router,
    private cd: ChangeDetectorRef,
  ) {}

  ngOnInit() {
    this.menuSrv.openedByUrl(this.router.url);
    this.menuChange$ = this.menuSrv.change.subscribe(res => {
      this.list = res;
      this.cd.detectChanges();
    });
    this.reuseChange$ = this.reuseSrv.change.subscribe(res => {
      this.updateOpen();
      this.cd.detectChanges();
    });
    this.installUnderPad();
  }

  updateOpen() {
    const currentLink = this.router.url;
    let imenu: Nav;
    this.menuSrv.visit((i, p) => {
      if (i.link === currentLink) {
        imenu = i;
      } else {
        i._open = false;
      }
    });
    while (imenu) {
      imenu._open = true;
      imenu = imenu.__parent;
    }
    this.cd.markForCheck();
  }

  onSelect(item: Nav) {
    this.select.emit(item);
    if (item._type === 1) {
      this.router.navigateByUrl(item.link);
    } else if (item._type === 2) {
      // ......
    }
  }

  ngOnDestroy(): void {
    this.menuChange$.unsubscribe();
    this.reuseChange$.unsubscribe();
    if (this.route$) {
      this.route$.unsubscribe();
    }
  }

  // region: Under pad

  private route$: Subscription;
  private installUnderPad() {
    if (!this.autoCloseUnderPad) return;
    this.route$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(s => this.underPad());
    this.underPad();
  }

  private underPad() {
    if (window.innerWidth < 992 && !this.settings.layout.collapsed) {
      this.settings.setLayout('collapsed', true);
    }
  }

  // endregion
}

四. 组件替换

将 layout/default/sidebar/sidebar.component.html 中的替换成

五. 样式调整

  1. 因为 ng-zorro-antd 的 nz-menu 折叠后的默认宽度是 80px,而 ng-alain 框架预留的宽度是64px,所以需要在 theme.less 中添加 @menu-collapsed-width: 64px; 修改 nz-menu 的宽度
  2. 菜单收缩后会显示半截 title 的问题,因为 ng-zorro-antd 有一套自己的图标规范,因此按照它的规范使用,不建议在代码中对 添加 margin-right
  3. 目前因为 angular 的问题,不限层级的写法还存在问题,因此默认写死最多展示三级,具体情况代码中我写的已经很清楚了

六. 与 sidebar-nav 的API 不兼容的问题

  1. 不支持 tooltip 和 badge,因为 ng-zorro-antd 并没有此功能,所以我没有花额外的时间去整合它,若你需要它,你只需稍微改动 sidebar-menu.component.html 即可
  2. 关于 externalLink 和 target ,我并不清楚应用场景,所以也未作深究,你可以修改 sidebar-menu.component.ts 中的 onSelect 方法去实现它

你可能感兴趣的:(将 ng-alain 中的菜单替换成 ng-zorro-antd 的 nz-menu)