You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何扩展Angular的mat-side-nav组件并确定必填参数?

创建可复用的Angular Material侧边导航组件

我懂你想要基于Angular Material的mat-sidenav系列组件打造一个可复用的侧边导航,同时严格遵守它的结构规则——mat-sidenav和mat-sidenav-content必须是mat-sidenav-container的直接子元素。下面我会一步步带你实现组件封装(这是Angular中更推荐的复用方式,而非直接继承原生组件),并明确必填和推荐配置的参数:

1. 先搭好组件的基础结构

首先用Angular CLI生成一个可复用组件(建议放到shared公共目录下):

ng generate component shared/sidebar

然后修改组件的模板文件,必须严格遵循Angular Material的结构要求,同时通过Angular的内容投影(ng-content)把可变部分暴露给父组件:

<mat-sidenav-container class="sidebar-container">
  <!-- 侧边栏区域 -->
  <mat-sidenav
    [mode]="mode"
    [opened]="opened"
    [position]="position"
    [hasBackdrop]="hasBackdrop"
    (openedChange)="onOpenedChange($event)"
    (closed)="closed.emit()"
  >
    <!-- 投影侧边栏自定义内容 -->
    <ng-content select="[sidebar-content]"></ng-content>
  </mat-sidenav>

  <!-- 主内容区域 -->
  <mat-sidenav-content>
    <!-- 投影主内容 -->
    <ng-content select="[main-content]"></ng-content>
  </mat-sidenav-content>
</mat-sidenav-container>

2. 在TypeScript中封装组件逻辑

我们不需要直接继承MatSidenav或MatSidenavContainer,而是通过@Input()和@Output()属性暴露原生组件的核心API,同时添加业务所需的自定义参数。以下是组件类的核心代码:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { MatSidenavMode } from '@angular/material/sidenav';

// 可选:定义菜单数据的接口,方便业务复用
export interface SidebarMenuItem {
  label: string;
  route: string;
  icon?: string;
}

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent {
  // --- 原生mat-sidenav的配置参数(带默认值,可覆盖)---
  @Input() mode: MatSidenavMode = 'side'; // 侧边栏模式:over/push/side
  @Input() opened = true; // 默认是否展开
  @Input() position: 'start' | 'end' = 'start'; // 侧边栏位置:左侧/右侧
  @Input() hasBackdrop = true; // 是否显示遮罩层
  @Input() fixedInViewport = false; // 是否固定在视口内

  // --- 业务必填参数(无默认值,父组件必须传入)---
  @Input() sidebarTitle!: string; // 侧边栏标题(业务中必填)
  @Input() menuItems!: SidebarMenuItem[]; // 侧边栏菜单数据(业务中必填)

  // --- 事件输出 ---
  @Output() openedChange = new EventEmitter<boolean>();
  @Output() closed = new EventEmitter<void>();

  onOpenedChange(isOpened: boolean) {
    this.openedChange.emit(isOpened);
  }
}

3. 明确必填参数与可选参数

核心必填参数(无默认值,必须传入)

这些是根据业务复用需求定义的,确保组件能正常展示核心内容:

  • sidebarTitle: string:侧边栏的标题文本,比如"系统导航"
  • menuItems: SidebarMenuItem[]:侧边栏的菜单数据数组,包含每个菜单项的标签、路由、图标等信息

可选配置参数(带默认值,按需覆盖)

这些是封装了mat-sidenav原生的配置项,你可以根据场景调整:

  • mode: MatSidenavMode:侧边栏的显示模式,默认side(与主内容并排),可选over(覆盖主内容)、push(推开主内容)
  • opened: boolean:默认是否展开侧边栏,默认true
  • position: 'start' | 'end':侧边栏的位置,默认左侧(start),可选右侧(end)

4. 使用可复用组件的示例

在父组件中调用这个侧边栏组件,传入必填参数并投影自定义内容:

<app-sidebar
  [sidebarTitle]="'系统菜单'"
  [menuItems]="sidebarMenus"
  [mode]="'push'"
  [opened]="isSidebarOpen"
  (openedChange)="isSidebarOpen = $event"
>
  <!-- 自定义侧边栏内容(比如标题区) -->
  <div sidebar-content>
    <h2 class="sidebar-title">{{sidebarTitle}}</h2>
    <mat-nav-list>
      <a mat-list-item *ngFor="let item of menuItems" [routerLink]="item.route">
        <mat-icon matListItemIcon>{{item.icon}}</mat-icon>
        <span matListItemTitle>{{item.label}}</span>
      </a>
    </mat-nav-list>
  </div>

  <!-- 主内容区域 -->
  <div main-content>
    <header class="app-header">
      <button mat-icon-button (click)="isSidebarOpen = !isSidebarOpen">
        <mat-icon>menu</mat-icon>
      </button>
      <span>我的应用</span>
    </header>
    <router-outlet></router-outlet>
  </div>
</app-sidebar>

关键注意事项

  • 绝对不能在mat-sidenav-container和mat-sidenav/mat-sidenav-content之间嵌套其他容器(比如div),否则Angular Material的布局逻辑会失效,这是官方明确要求的结构规则。
  • 如果需要自定义样式,可以给mat-sidenav-container、mat-sidenav添加类名,在组件的样式文件中修改;如果需要穿透Angular的视图封装,可以使用:host ::ng-deep(注意Angular版本兼容性)。

内容的提问来源于stack exchange,提问作者Charlie-Greenman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:19:22