Angular4实现自定义模板渲染无限嵌套树的通用组件问询
嘿,我来帮你搞定这个Angular 4的递归组件问题!你想要的通用递归列表组件完全可以实现,现在内部元素没显示,核心原因是你没把外部传入的模板传递给递归的子组件,下面是具体的解决思路和修正代码:
你当前的代码逻辑没问题,但递归调用<novo-rec-list-view>时,没有把父组件传入的itemTemplate传递给子组件。子组件找不到对应的模板引用,自然无法渲染深层级的节点内容。
Angular 4完全支持这种「通用递归逻辑+自定义节点模板」的模式,我们只需要确保模板能在递归层级中正确传递,具体步骤如下:
1. 改造递归组件,支持模板传递
首先修改novo-rec-list-view.component.ts,添加对外部模板的引用接收:
import { Component, Input, ContentChild, TemplateRef } from '@angular/core'; @Component({ selector: 'novo-rec-list-view', templateUrl: './novo-rec-list-view.component.html' }) export class NovoRecListViewComponent { @Input() recursionKey: string; @Input() dataSource: any[] = []; // 通过ContentChild获取外部传入的模板引用 @ContentChild('itemTemplate') itemTemplate: TemplateRef<any>; }
然后更新组件模板novo-rec-list-view.component.html,确保递归调用时把模板传递给子组件(这里用内容投影的方式,贴合你原本的写法):
<div *ngIf="dataSource && dataSource.length > 0"> <div *ngFor="let item of dataSource; let i = index"> <!-- 渲染当前节点的自定义模板 --> <ng-template [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, index: i }"> </ng-template> <!-- 递归调用子组件,同时把模板传递下去 --> <novo-rec-list-view *ngIf="item[recursionKey] && item[recursionKey].length > 0" [recursionKey]="recursionKey" [dataSource]="item[recursionKey]"> <!-- 复用当前模板作为子组件的内容 --> <ng-template #itemTemplate let-item="$implicit" let-i="index"> <ng-template [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, index: i }"></ng-template> </ng-template> </novo-rec-list-view> </div> </div>
如果你觉得内容投影的写法有点绕,也可以把模板作为输入属性传递,代码会更直观:
修改组件类,替换@ContentChild为输入属性:
@Input() itemTemplate: TemplateRef<any>;
然后模板里递归时直接绑定:
<div *ngIf="dataSource && dataSource.length > 0"> <div *ngFor="let item of dataSource; let i = index"> <ng-template [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, index: i }"> </ng-template> <novo-rec-list-view *ngIf="item[recursionKey] && item[recursionKey].length > 0" [recursionKey]="recursionKey" [dataSource]="item[recursionKey]" [itemTemplate]="itemTemplate"> </novo-rec-list-view> </div> </div>
对应的使用方式调整为:
<novo-rec-list-view id="change-log-list" [recursionKey]="recursionKey" [dataSource]="treeNodeList" [itemTemplate]="itemTemplate"> </novo-rec-list-view> <ng-template #itemTemplate let-item="$implicit" let-i="index"> <change-log-cell [item]="item"></change-log-cell> </ng-template>
2. 确保递归组件的正确声明
在Angular 4中,递归组件必须在你的NgModule的declarations数组中声明,确保框架能正确识别它:
@NgModule({ declarations: [ AppComponent, NovoRecListViewComponent, ChangeLogCellComponent ], // ...其他配置(如imports、bootstrap等) }) export class AppModule { }
3. 处理空数据边界
在模板中添加空值判断,避免item[recursionKey]为undefined时出现报错,比如上面代码里的*ngIf="item[recursionKey] && item[recursionKey].length > 0",这样只有当子节点存在数据时才会渲染递归组件。
经过上述修改后,你的递归组件应该能正确渲染所有层级的节点,每个节点都会使用你自定义的change-log-cell组件布局。这种方式完全解耦了递归逻辑和节点渲染逻辑,你可以在应用的任何地方复用novo-rec-list-view组件,只需要传入不同的模板即可实现不同的节点样式。
内容的提问来源于stack exchange,提问作者Ashish Dulhani

