从后台返回的数据,还有多层子节点,需要一个生成树的组件,如果直接在页面上写循环来拼接感觉会很麻烦,因为数据的层级结构不固定。
参考网上其他人的方法,整理如下:
1. 创建一个用于循环迭代的组件,在父组件的元素上绑定需要递归的数据和递归组件的选择器。
<ul class="list-wrapper" [treeData]="circuitList" [originalData]="circuitList" (sendNode)="getCurrentNode($event)" tpl-tree-node></ul>
2. 在递归的子组件中接收父组件传入的数据,并在其模板中调用递归组件自身:
<li *ngFor="let item of treeData"> <a [ngClass]="{'active':item.active}" (click)="getCurrentNode(item)"> <span class="glyphicon mini-icon" *ngIf="item.children" (click)="toggleSubNode(item)" [ngClass]="{'glyphicon-triangle-bottom':item.open,'glyphicon-triangle-right':!item.open}"></span>{{item.name}}</a> <ul *ngIf="item.children" [ngClass]="{'show':item.open,'hidden':!item.open}" [treeData]="item.children" (sendNode)="getCurrentNode($event)" [originalData]="treeData" tpl-tree-node></ul> </li>
子组件的ts代码
import {Component, EventEmitter, Input, Output} from "@angular/core"; @Component({ selector: '[tpl-tree-node]', templateUrl: './tpl-tree-node.component.html', styleUrls: ['./tpl-tree-node.component.css'] }) export class TplTreeNodeComponent { @Input() treeData = []; @Input() originalData; @Output() sendNode: EventEmitter<any> = new EventEmitter<any>(); constructor() { } getCurrentNode(item) { this._formatList(this.originalData); item.active = true; this.sendNode.emit(item); } private _formatList(arr) { arr.forEach(node => { node.active = false; if (node.children) this._formatList(node.children); }); } toggleSubNode(item) { item.open = !item.open; } }
按照以上,树组件已经可以正常生成。
同时在点击节点时添加一个激活的样式,取消掉其他节点的激活样式,并将节点对应的数据发送到父组件。
这里比较特别的是递归组件的选择器的定义:
selector: '[tpl-tree-node]',
3. 与参考链接里面不同的是,多定义了一个@Input() originalData,并在子组件中也绑定了这个属性。
这里是为了取消其他树节点的激活样式。不绑定这个初始数据的话,节点点击时,传入的treeData会变成绑定的item.children的数据。即只处理当前节点并列及以下子节点的状态。
4. 从子组建中发送事件到父组件时,一开始没有在子组件内部迭代的部分也绑定事件,导致部分子节点不会发送事件。
参考链接:https://blog.csdn.net/oneloser/article/details/92086914