完成的效果:
树组件的目录结构:
树组件的结构非常简单,仅需要一个组件即可完成。
Tree组件:
先放下代码:
代码语言:javascript复制<div class="TreeBase">
<div class="TreeNode">
<div [class]="'NodeSelect' ' NodeSelect_' (TreeData[DefaultConfig.Select] || false)" (click)="SelectClick(TreeData)"></div>
<div class="NodeName Cursor ExWidth" (click)="ExplandClick(TreeData)">
<span class="Span NameSpan" [title]="TreeData[DefaultConfig.Name]">{{ TreeData[DefaultConfig.Name] }}</span>
</div>
<div *ngIf="TreeData[DefaultConfig.Member] && TreeData[DefaultConfig.Member].length > 0">
<div [class]="'NodeExpland NodeExpland_' (TreeData[DefaultConfig.Expland] || false)"></div>
</div>
</div>
<div *ngIf="TreeData[DefaultConfig.Member] && TreeData[DefaultConfig.Member].length > 0 && TreeData[DefaultConfig.Expland]" class="ChildNode">
<div *ngFor="let MemberData of TreeData[DefaultConfig.Member]">
<app-Tree [TreeData]="MemberData" (NodeClickEvent)="NodeClickEventEmit($event)" [Name]="DefaultConfig.Name" [Code]="DefaultConfig.Code"></app-Tree>
</div>
</div>
</div>
代码语言:javascript复制import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-Tree',
templateUrl: './Tree.component.html',
styleUrls: ['./Tree.component.css']
})
export class TreeComponent implements OnInit {
DefaultConfig: any;
@Input() TreeData: any;
@Input() Name: string;
@Input() Code: string;
@Input() Member: string;
@Output() NodeClickEvent = new EventEmitter<any>();
constructor(
) { }
ngOnInit() {
this.DefaultConfig = {
Name: this.Name || "Name",
Code: this.Code || "Code",
Member: this.Member || "Member",
Select: "Select",
Expland: "Expland",
}
}
ExplandClick(event: any) {
if (event[this.DefaultConfig.Member] && event[this.DefaultConfig.Member].length > 0) {
event[this.DefaultConfig.Expland] = !(event[this.DefaultConfig.Expland] || false);
}
}
SelectClick(event: any) {
event[this.DefaultConfig.Select] = !event[this.DefaultConfig.Select];
this.NodeClickEvent.emit(event);
}
NodeClickEventEmit(event: any) {
this.NodeClickEvent.emit(event);
}
}
代码语言:javascript复制.TreeBase {
width: 100%;
float: right;
}
.TreeNode {
height: 33px;
width: 100%;
}
.NodeSelect {
float: left;
height: 16px;
width: 16px;
margin-left: 7px;
margin-top: 8px;
margin-right: 7px;
}
.NodeSelect_true {
cursor: pointer;
background: url('./Resource/Icon-select.png') no-repeat center center;
}
.NodeSelect_false {
cursor: pointer;
background: url('./Resource/Icon-unselect.png') no-repeat center center;
}
.NodeName {
float: left;
margin-top: 5px;
height: 22px;
}
.ExWidth {
width: calc(100% - 54px);
}
.Width {
width: calc(100% - 40px);
}
.Cursor {
cursor: pointer;
}
.NodeExpland {
float: left;
width: 16px;
height: 16px;
margin-top: 8px;
margin-left: 4px;
margin-right: 4px;
}
.NodeExpland_true {
background: url('./Resource/Explanded.png') no-repeat center center;
}
.NodeExpland_false {
background: url('./Resource/Expland.png') no-repeat center center;
}
.Span {
font-family: PingFang SC Regular;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
user-select: none;
}
.NameSpan {
font-size: 16px;
height: 22px;
color: rgba(255, 255, 255, 1);
}
.ChildNode {
float: right;
width: 90%;
}
首先要注意的是this.DefaultConfig这个配置。一般来说,展示数据需要两个属性:Name和Code,Name是该节点在界面上展示的文字,他是可以重复的,展示的时候也会考虑添加一些符合用户阅读习惯的信息。Code是该节点的主键,即是使用树组件时判断选中了哪个节点的唯一标识。开发过程中,使用的数据结构并不一定恰好是Name和Code,因此允许开发者指定自己数据结构中对应功能的属性名。Member是该节点的子节点列表。同样我们允许开发者指定属性名。TreeData是用户需要展示的数据。
观察html中包含两个部分。
class=“TreeNode”中实现了传入节点本身的样式。
class=“ChildNode”中为每个子节点递归调用了树组件。同样注意要把用户指定的参数名继续传递下去。
注意NodeClickEvent在递归调用树组件时,内部的节点被点击时,点击事件会一层一层的传递到最外层。
在其他页面使用树组件:
代码语言:javascript复制 <div style="height: 500px;width: 300px;background: rgba(29, 51, 76, 1);">
<app-Tree [TreeData]="TreeData" (NodeClickEvent)="NodeClickEventEmit($event)" [Name]="'Name'" [Code]="'Code'" [Member]="'Member'"></app-Tree>
</div>
代码语言:javascript复制import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.css']
})
export class IndexComponent implements OnInit {
TreeData = {
Name: "学校",
Code: "School",
Member: [
{
Name: "高二一班", Code: "C21", Member: [
{ Name: "小明", Code: "S01" },
{ Name: "小红", Code: "S02" },
{ Name: "小刚", Code: "S03" },
]
}, {
Name: "高二二班", Code: "C21", Member: [
{ Name: "大明", Code: "S04" },
{ Name: "大红", Code: "S05" },
{ Name: "大刚", Code: "S06" },
]
},
{ Name: "高二三班", Code: "C21" },
{ Name: "高二四班", Code: "C21" },
]
}
ngOnInit() {
}
NodeClickEventEmit(event: any) {
console.log("SelectNode-->", event);
}
}
模拟了一个学校-班级-学生的树结构数据。
这样一个简单的树组件就封装完成了!