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:默认是否展开侧边栏,默认trueposition: '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
相关产品推荐
相关产品推荐

