Angular中大量使用*ngIf的优化方案咨询:侧边导航内容切换
嘿,我来帮你搞定这个问题!你提到的大量用*ngIf导致模板乱糟糟的情况,在Angular开发里太常见了,尤其是这种侧边导航切换内容的场景。下面给你分享两种靠谱的优化方案,重点是你想要的动态组件实现,一步步来:
一、基础优化:用
ngSwitch替代一堆*ngIf 如果你的内容组件数量不多,ngSwitch比零散的*ngIf更清晰,能让模板结构更规整,可读性更好:
<div class="container-fluid"> <div class="row"> <div class="d-none d-md-block col-md-2 sidemenu"> <app-sidemenu (menuClick)="display = $event"></app-sidemenu> </div> <div class="col-md-10 content-area" [ngSwitch]="display"> <app-user-list *ngSwitchCase="'userList'"></app-user-list> <app-settings *ngSwitchCase="'settings'"></app-settings> <app-dashboard *ngSwitchDefault></app-dashboard> </div> </div> </div>
这种方式只是让模板更整洁,但本质还是静态条件渲染,组件数量多了之后依然会有冗余代码。接下来是你想要的动态组件方案,这才是处理大量内容切换的最优解。
二、最优解:动态组件实现(类似
app-{{display}}的效果) Angular提供了两种动态渲染组件的方式,推荐优先用最新的*ngComponentOutlet指令(Angular 13+支持),代码极简;如果是老版本,再用ComponentFactoryResolver手动创建组件。
方案1:用*ngComponentOutlet(推荐)
这是官方内置的指令,直接帮你搞定动态组件的渲染,不需要写复杂的工厂代码。
步骤1:在宿主组件中维护组件映射表
先把要切换的组件和对应的key关联起来,方便根据侧边导航的选择找到对应组件:
import { Component, Type } from '@angular/core'; import { UserListComponent } from './user-list/user-list.component'; import { SettingsComponent } from './settings/settings.component'; import { DashboardComponent } from './dashboard/dashboard.component'; @Component({ selector: 'app-main-layout', templateUrl: './main-layout.component.html' }) export class MainLayoutComponent { // 组件映射表:key对应侧边导航的标识,值是组件类 componentMap: Record<string, Type<any>> = { 'userList': UserListComponent, 'settings': SettingsComponent, 'dashboard': DashboardComponent }; currentComponent: Type<any> = this.componentMap['dashboard']; // 默认显示仪表盘 display: string = 'dashboard'; // 侧边导航点击事件处理 onSideMenuClick(menuKey: string) { this.display = menuKey; this.currentComponent = this.componentMap[menuKey]; } }
步骤2:在模板中用*ngComponentOutlet渲染
直接把当前要显示的组件传给指令就行:
<div class="container-fluid"> <div class="row"> <div class="d-none d-md-block col-md-2 sidemenu"> <app-sidemenu (menuItemClick)="onSideMenuClick($event)"></app-sidemenu> </div> <div class="col-md-10 content-area"> <!-- 动态渲染组件 --> <ng-container *ngComponentOutlet="currentComponent"></ng-container> </div> </div> </div>
进阶:给动态组件传值/监听事件
如果需要给动态组件传递数据或者监听它的事件,Angular 14+支持直接在指令里绑定:
<ng-container *ngComponentOutlet="currentComponent; inputs: { userInfo: currentUser }; outputs: { save: handleSave($event) }" ></ng-container>
或者你也可以通过组件实例手动绑定(适合所有版本):
// 先获取组件引用(需要用ViewChild拿到容器) @ViewChild('dynamicContainer', { read: ViewContainerRef }) dynamicContainer!: ViewContainerRef; onSideMenuClick(menuKey: string) { this.dynamicContainer.clear(); // 清空旧组件 const componentRef = this.dynamicContainer.createComponent(this.componentMap[menuKey]); // 传值 componentRef.instance.userInfo = this.currentUser; // 监听事件 componentRef.instance.save.subscribe((data) => { this.handleSave(data); }); }
方案2:老版本Angular用ComponentFactoryResolver
如果你的项目是Angular 12及以下版本,就需要用这种手动创建组件工厂的方式:
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, Type } from '@angular/core'; // 导入你的组件... @Component({ selector: 'app-main-layout', templateUrl: './main-layout.component.html' }) export class MainLayoutComponent { componentMap = { 'userList': UserListComponent, 'settings': SettingsComponent, 'dashboard': DashboardComponent }; @ViewChild('dynamicContent', { read: ViewContainerRef }) dynamicContent!: ViewContainerRef; constructor(private cfr: ComponentFactoryResolver) {} onSideMenuClick(menuKey: string) { this.dynamicContent.clear(); // 创建组件工厂 const factory = this.cfr.resolveComponentFactory(this.componentMap[menuKey]); // 渲染组件 this.dynamicContent.createComponent(factory); } }
模板里需要给容器加个模板引用:
<div class="col-md-10 content-area"> <div #dynamicContent></div> </div>
额外优化:懒加载动态组件
如果你的组件体积比较大,可以用动态导入实现懒加载,减少首屏包体积:
// 把组件映射表改成异步加载函数 componentMap: Record<string, () => Promise<Type<any>>> = { 'userList': () => import('./user-list/user-list.component').then(m => m.UserListComponent), 'settings': () => import('./settings/settings.component').then(m => m.SettingsComponent), }; // 切换组件时异步加载 async onSideMenuClick(menuKey: string) { const componentModule = await this.componentMap[menuKey](); this.currentComponent = componentModule; }
总结
- 组件数量少的时候,
ngSwitch比一堆*ngIf更整洁; - 组件数量多或者需要灵活控制时,动态组件是最优解,尤其是
*ngComponentOutlet,代码简洁且官方推荐; - 动态组件还支持懒加载、数据传递、事件监听,完全满足你侧边导航切换内容的需求。
内容的提问来源于stack exchange,提问作者user5096599
相关产品推荐
相关产品推荐

