项目

修改菜单

菜单位于 @abp/ng.theme.basic 包的 ApplicationLayoutComponent 中。有几种方法可以修改菜单元素。本文档将介绍这些方法。如果您想完全替换菜单,请参考组件替换文档,了解如何替换布局。

如何添加徽标

环境变量中的 logoUrl 属性是徽标的URL。

您可以将徽标添加到 src/assets 文件夹,并按如下所示设置 logoUrl

export const environment = {
  // 其他配置
  application: {
    name: 'MyProjectName',
    logoUrl: 'assets/logo.png',
  },
  // 其他配置
};

然后,在应用程序启动时使用 Theme Shared 提供者提供徽标。这使得徽标(和应用程序名称)可以通过注入令牌供所有 ABP/Theme 组件(包括 LeptonX 品牌组件)使用。

// app.config.ts
import { provideLogo, withEnvironmentOptions } from '@abp/ng.theme.shared';
import { environment } from './environments/environment';

export const appConfig: ApplicationConfig = {
  providers: [
    // ... 其他提供者
    provideLogo(withEnvironmentOptions(environment)),
  ],
};

注意事项

  • 此方法适用于所有主题。如果您使用 LeptonX,品牌徽标组件会自动读取这些值;您不需要任何特定于主题的代码。
  • 如果需要,您仍然可以使用 CSS 变量覆盖视觉效果。有关 CSS 覆盖,请参阅 LeptonX 部分。

如何添加导航元素

通过 RoutesService

您可以通过调用 RoutesServiceadd 方法向菜单添加路由。它是一个单例服务,即在根目录提供,因此您可以立即注入并使用它。

import { RoutesService, eLayoutType } from '@abp/ng.core';
import { Component, inject } from '@angular/core';

@Component(/* 组件元数据 */)
export class AppComponent {
  private routes = inject(RoutesService);

  constructor() {
    this.routes.add([
      {
        path: '/your-path',
        name: '您的导航',
        order: 101,
        iconClass: 'fas fa-question-circle',
        requiredPolicy: '此处填写权限密钥',
        layout: eLayoutType.application,
      },
      {
        path: '/your-path/child',
        name: '您的子导航',
        parentName: '您的导航',
        order: 1,
        requiredPolicy: '此处填写权限密钥',
      },
    ]);
  }
}

另一种可能更简洁的方法是使用路由提供者。首先创建一个提供者:

// route.provider.ts
import { RoutesService, eLayoutType } from '@abp/ng.core';
import { provideAppInitializer } from '@angular/core';

export const APP_ROUTE_PROVIDER = [
  provideAppInitializer(() => {
    configureRoutes();
  }),
];

function configureRoutes() {
  const routesService = inject(RoutesService);
  routes.add([
    {
      path: '/your-path',
      name: '您的导航',
      requiredPolicy: '此处填写权限密钥',
      order: 101,
      iconClass: 'fas fa-question-circle',
      layout: eLayoutType.application,
    },
    {
      path: '/your-path/child',
      name: '您的子导航',
      parentName: '您的导航',
      requiredPolicy: '此处填写权限密钥',
      order: 1,
    },
  ]);
}

我们还可以为导航元素定义一个组。这是一个可选属性。

  • 注意: 它还将包含在模块中定义的组。
// route.provider.ts
import { RoutesService } from '@abp/ng.core';

function configureRoutes() {
  const routesService = inject(RoutesService);
  routes.add([
    {
      //等等..
      group: '模块名::组名'
    },
    {
      path: '/your-path/child',
      name: '您的子导航',
      parentName: '您的导航',
      requiredPolicy: '此处填写权限密钥',
      order: 1,
    },
  ]);
}

要获取分组的路由项,我们可以使用 groupedVisible(或可观察版本 groupedVisible$) getter 方法。

  • 如果路由树中存在任何组,则返回 RouteGroup<T>[],否则返回 undefined
import { ABP, RoutesService, RouteGroup } from "@abp/ng.core";
import { Component, inject } from "@angular/core";
import { Observable } from "rxjs";

@Component(/* 组件元数据 */)
export class AppComponent {
  private routes = inject(RoutesService);

  visible: RouteGroup<ABP.Route>[] | undefined = this.routes.groupedVisible;
  // 或者
  visible$: Observable<RouteGroup<ABP.Route>[] | undefined> = this.routes.groupedVisible$;
}

...然后在 app.config.ts 中...

  • groupedVisible 方法将为未分组的项返回 Others 组,默认键是 AbpUi::OthersGroup,我们可以通过 OTHERS_GROUP 注入令牌更改此 key
import { OTHERS_GROUP } from '@abp/ng.core';
import { APP_ROUTE_PROVIDER } from './route.provider';

export const appConfig: ApplicationConfig = {
  providers: [
    // ...
    APP_ROUTE_PROVIDER,
    {
      provide: OTHERS_GROUP,
      useValue: '模块名::MyOthersGroupKey',
    },
  ],
};

路由项单一化

  • name 属性必须是唯一的键。如果存在多个具有相同名称的项,菜单中将显示最后一个。
  • 如果您想在不同父级下显示多个同名的项,可以调用 RoutesServicesetSingularizeStatus(false) 方法来禁用单一化。
    • 此方法应在添加路由之前调用。
  • 要启用名称的单一化,可以调用 RoutesServicesetSingularizeStatus(true) (默认值: true) 方法。
import { RoutesService } from '@abp/ng.core';
import { Component, inject } from '@angular/core';

@Component(/* 组件元数据 */)
export class AppComponent {
  private routes = inject(RoutesService);

  constructor() {
    this.routes.setSingularizeStatus(false);
  }
}

以下是每个属性的作用:

  • path 是导航元素的绝对路径。
  • name 是导航元素的标签。可以传递本地化键或本地化对象。
  • parentName 是对菜单中父路由 name 的引用,用于创建多级菜单项。
  • requiredPolicy 是访问页面所需的权限密钥。请参阅权限管理文档
  • order 是导航元素的顺序。"Administration" 的 order 为 100,因此在排序顶级菜单项时请记住这一点。
  • iconClassi 标签的类,该标签放置在导航标签的左侧。
  • layout 定义路由在哪个布局中加载。(默认: eLayoutType.empty)
  • invisible 使项在菜单中不可见。(默认: false)
  • group 是一个可选属性,用于在应用程序中对相关路由进行分组。(类型: string, 默认: AbpUi::OthersGroup)

通过 APP_ROUTES 中的 routes 属性

您可以通过在 app.routes.ts 中的路由配置的 data 属性下添加 routes 作为子属性来定义您的路由。@abp/ng.core 包会组织您的路由并将其存储在 RoutesService 中。

您可以像下面这样添加 routes 属性:

{
  path: 'your-path',
  data: {
    routes: {
      name: '您的导航',
      order: 101,
      iconClass: 'fas fa-question-circle',
      requiredPolicy: '此处填写权限密钥',
      children: [
        {
          path: 'child',
          name: '您的子导航',
          order: 1,
          requiredPolicy: '此处填写权限密钥',
        },
      ],
    },
  },
}

或者,您可以这样做:

{
  path: 'your-path',
  data: {
    routes: [
      {
        path: '/your-path',
        name: '您的导航',
        order: 101,
        iconClass: 'fas fa-question-circle',
        requiredPolicy: '此处填写权限密钥',
      },
      {
        path: '/your-path/child',
        name: '您的子导航',
        parentName: '您的导航',
        order: 1,
        requiredPolicy: '此处填写权限密钥',
      },
    ] as ABP.Route[], // 可以从 @abp/ng.core 导入
  },
}

第二种方法的优点是您不受父/子结构的约束,可以使用任何您喜欢的路径。

按照上述方式添加 routes 属性后,导航菜单将如下所示:

通过应用路由的导航菜单

如何修补或移除导航元素

RoutesServicepatch 方法通过名称查找路由,并使用作为第二个参数传递的新配置替换其配置。类似地,remove 方法查找路由并将其及其子项一起移除。您还可以使用 removeByParam 方法删除具有给定属性的路由。

// this.routes 是 RoutesService 的实例
// eThemeSharedRouteNames 枚举可以从 @abp/ng.theme.shared 导入

const dashboardRouteConfig: ABP.Route = {
  path: '/dashboard',
  name: '::Menu:Dashboard',
  parentName: '::Menu:Home',
  order: 1,
  layout: eLayoutType.application,
};

const newHomeRouteConfig: Partial<ABP.Route> = {
  iconClass: 'fas fa-home',
  parentName: eThemeSharedRouteNames.Administration,
  order: 0,
};

this.routes.add([dashboardRouteConfig]);
this.routes.patch('::Menu:Home', newHomeRouteConfig);
this.routes.remove(['您的导航']);

// 或
this.routes.removeByParam({ name: '您的导航' });

方法参数:

  • remove(routeNames: string[]): 接受要移除的路由名称数组。
  • removeByParam(routeProperty: Partial<ABP.Route>): 接受任何路由属性(name、path、parentName 等)来匹配和移除路由。

上述操作的结果:

  • 根据给定的 parentName,将 Home 导航移至 Administration 下拉菜单下。
  • Home 添加了一个图标。
  • 指定了顺序,使 Home 成为列表中的第一项。
  • 添加了一个名为 Dashboard 的路由作为 Home 的子项。
  • 移除了 您的导航 及其子路由。

上述操作后,新菜单如下所示:

修补后的导航菜单

如何在菜单右侧添加元素

您可以通过调用 NavItemsServiceaddItems 方法向菜单右侧添加元素。它是一个单例服务,即在根目录提供,因此您可以立即注入并使用它。

import { NavItemsService } from '@abp/ng.theme.shared';
import { Component, inject } from '@angular/core';

@Component({
  template: `
    <input type="search" placeholder="搜索" class="bg-transparent border-0 color-white" />
  `,
})
export class MySearchInputComponent {}


@Component(/* 组件元数据 */)
export class AppComponent {
  private navItems = inject(NavItemsService);

  constructor() {
    this.navItems.addItems([
      {
        id: 'MySearchInput',
        order: 1,
        component: MySearchInputComponent,
      },
      {
        id: 'SignOutIcon',
        html: '<i class="fas fa-sign-out-alt fa-lg text-white m-2"><i>',
        action: () => console.log('点击了退出图标'),
        order: 101, // 作为最后一个元素放置
      },
    ]);
  }
}

这将在菜单中插入一个搜索输入框和一个退出图标。最终UI如下所示:

导航菜单搜索输入

默认元素的顺序为 100。如果要在默认元素之前放置自定义元素,请分配一个最多为 99 的顺序号。如果要在默认元素之后放置自定义元素,请分配从 101 开始的顺序号。最后,如果必须在默认元素之间放置一个项,请按照下面的描述修补默认元素的顺序。但请注意:我们将来可能会添加另一个默认元素,其顺序号也为 100

如何修补或移除右侧元素

NavItemsServicepatchItem 方法通过其 id 属性查找元素,并使用作为第二个参数传递的新配置替换其配置。类似地,removeItem 方法查找元素并将其移除。

export class AppComponent {
  private navItems = inject(NavItemsService);

  constructor() {
    this.navItems.patchItem(eThemeBasicComponents.Languages, {
      requiredPolicy: '新的权限策略',
      order: 1,
    });

    this.navItems.removeItem(eThemeBasicComponents.CurrentUser);
  }
}
  • 使用新的 requiredPolicy 和新的 order 修补了语言下拉元素。
  • 移除了当前用户下拉元素。

分组菜单 (专业版)

此功能仅适用于 LeptonX 主题

Web

分组菜单

移动端

移动端分组菜单

在本文档中