Angular Material Tree
Angular Material是一个由谷歌开发的UI组件库,以便Angular开发人员能够以一种结构化和响应式的方式开发现代应用程序。通过使用这个库,我们可以大大增加终端用户的用户体验,从而为我们的应用程序赢得人气。这个库包含了现代的即用元素,可以直接使用,只需最少或没有额外的代码。
该<mat-tree>
指令用于在Angular中创建树。树是一种包含数据的结构类型,以分层的方式组织。每个数据项都由树的一个节点表示。Angular Material Tree是对以前的结构,即Component Dev Kit Tree(cdk-tree)的一种增强。在用户界面上呈现的树形结构能够将单个数据节点扩展和折叠成多级数据节点。该树是使用JSON对象动态创建的。有两种类型的树。
- Flat Tree
- Nested Tree
安装:
基本的前提条件是,我们必须在系统上安装Angular CLI,以便添加和配置Angular材料库。满足所需条件后,我们可以在Angular CLI上键入以下命令。
ng add @angular/material
详细的安装过程请参考在Angular应用程序中添加Angular材料组件的文章。
添加Mat-Tree组件:
- 为了使用扁平树组件,我们需要把它导入我们的组件文件,如下所示。
import { FlatTreeControl } from '@angular/cdk/tree';
- 为了使用嵌套树组件,我们需要把它导入我们的组件文件,如下所示。
import { NestedTreeControl } from '@angular/cdk/tree';
- 为了使用材料树模块,我们需要将其导入app.module.ts文件中。
import {MatTreeModule} from '@angular/material/tree';
在使用导入语句后,将_MatTreeModule _也添加到NgModule导入数组中。
扁平树:扁平树是一棵树,所有的节点都是以顺序的方式在DOM上呈现的。可以把它看作是以树的形式一个接一个地显示数组元素。由此产生的树有可以扩展/折叠的节点,DOM成为一个单深度的列表。
语法:
<mat-tree>
<mat-tree-node> Parent node name </mat-tree-node>
<mat-tree-node> Child Node 1 </mat-tree-node>
<mat-tree-node> Child Node 2 </mat-tree-node>
</mat-tree>
项目结构:安装成功后,项目结构将看起来像以下图片。
扁平树的项目结构
例子:下面的例子说明了Angular Material Flat Tree的实现。
import { Component, OnInit } from "@angular/core";
import { FlatTreeControl } from "@angular/cdk/tree";
import { MatTreeFlatDataSource, MatTreeFlattener }
from "@angular/material/tree";
interface Family {
name: string;
children?: Family[];
}
const FAMILY_TREE: Family[] = [
{
name: "Joyce",
children: [
{ name: "Mike" },
{ name: "Will" },
{ name: "Eleven", children: [{ name: "Hopper" }] },
{ name: "Lucas" },
{ name: "Dustin", children: [{ name: "Winona" }] },
],
},
{
name: "Jean",
children: [{ name: "Otis" }, { name: "Maeve" }],
},
];
/** Flat node with expandable and level information */
interface ExampleFlatNode {
expandable: boolean;
name: string;
level: number;
}
@Component({
selector: "app-flat-node-tree",
templateUrl: "./flat-node-tree.component.html",
styleUrls: ["./flat-node-tree.component.css"],
})
export class FlatNodeTreeComponent implements OnInit {
private _transformer = (node: Family, level: number) => {
return {
expandable: !!node.children && node.children.length > 0,
name: node.name,
level: level,
};
};
treeControl = new FlatTreeControl<ExampleFlatNode>(
(node) => node.level,
(node) => node.expandable
);
treeFlattener = new MatTreeFlattener(
this._transformer,
(node) => node.level,
(node) => node.expandable,
(node) => node.children
);
dataSource = new MatTreeFlatDataSource(
this.treeControl, this.treeFlattener);
constructor() {
this.dataSource.data = FAMILY_TREE;
}
hasChild = (_: number,
node: ExampleFlatNode) => node.expandable;
ngOnInit(): void {}
}
<h1>GeeksforGeeks</h1>
<h3>MatTree Example</h3>
<mat-tree [dataSource]="dataSource"
[treeControl]="treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
<!-- Adding disabled property to button
so as to give padding to nodes -->
<button mat-icon-button disabled></button>
{{node.name}}
</mat-tree-node>
<!-- Tree node template for expandable nodes -->
<mat-tree-node
*matTreeNodeDef="let node;when: hasChild"
matTreeNodePadding>
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]=
"'Toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ?
'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.name}}
</mat-tree-node>
</mat-tree>
h1, h3 {
color: green;
font-family: "Roboto", sans-serif;
text-align: center;
}
.mat-tree {
background: transparent;
}
.mat-tree-node {
color: black;
}
<app-flat-node-tree></app-flat-node-tree>
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
import { BrowserAnimationsModule }
from "@angular/platform-browser/animations";
import { FlatNodeTreeComponent }
from "./flat-node-tree/flat-node-tree.component";
import { MatTreeModule } from "@angular/material/tree";
import { MatIconModule } from "@angular/material/icon";
@NgModule({
declarations: [AppComponent, FlatNodeTreeComponent],
exports: [AppComponent],
imports: [
CommonModule,
BrowserAnimationsModule,
BrowserModule,
MatTreeModule,
MatIconModule,
],
bootstrap: [AppComponent],
})
export class AppModule {}
输出:
扁平节点树实例
嵌套树: 嵌套树是一棵树,所有的子节点都放在DOM的父节点里面。当我们有一个复杂的节点之间的关系,而扁平的树无法创建所需的结构时,可以最好地使用嵌套树。每个父节点都有自己的出口来定义子节点。
语法:
<mat-tree>
<mat-nested-tree-node>
Parent node name
<mat-nested-tree-node> Child Node 1 </mat-nested-tree-node>
<mat-nested-tree-node> Child Node 2 </mat-nested-tree-node>
.
.
.
<mat-nested-tree-node> Child Node N </mat-nested-tree-node>
</mat-nested-tree-node>
</mat-tree>
项目结构:安装成功后,项目结构将看起来像以下图片。
嵌套树的项目结构
例子:下面的例子说明了Angular Material Nested tree的实现。
import { Component, OnInit } from "@angular/core";
import { NestedTreeControl } from "@angular/cdk/tree";
import { MatTreeNestedDataSource } from "@angular/material/tree";
interface Smartphone {
parent_company: string;
sub_brand?: Smartphone[];
}
const TREE_DATA: Smartphone[] = [
{
parent_company: "Xiaomi",
sub_brand: [
{ parent_company: "Poco" },
{ parent_company: "Redmi" },
{ parent_company: "Mijia" },
],
},
{
parent_company: "BBK Electronics",
sub_brand: [
{
parent_company: "Vivo",
sub_brand: [{ parent_company: "iQoo" }],
},
{
parent_company: "Oppo",
sub_brand: [{ parent_company: "Realme" },
{ parent_company: "Dizo" }],
},
],
},
];
@Component({
selector: "app-nested-tree-example",
templateUrl: "./nested-tree-example.component.html",
styleUrls: ["./nested-tree-example.component.css"],
})
export class NestedTreeExampleComponent implements OnInit {
treeControl = new NestedTreeControl<Smartphone>((node) => node.sub_brand);
dataSource = new MatTreeNestedDataSource<Smartphone>();
constructor() {
this.dataSource.data = TREE_DATA;
}
hasChild = (_: number, node: Smartphone) =>
!!node.sub_brand && node.sub_brand.length > 0;
ngOnInit(): void {}
}
<h1>GeeksforGeeks</h1>
<h3>Nested Tree Example</h3>
<mat-tree [dataSource]="dataSource"
[treeControl]="treeControl"
class="example-tree">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
{{node.parent_company}}
</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle [attr.aria-label]=
"'Toggle ' + node.parent_company">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.parent_company}}
</div>
<div [class.example-tree-invisible]=
"!treeControl.isExpanded(node)" role="group">
<ng-container matTreeNodeOutlet></ng-container>
</div>
</mat-nested-tree-node>
</mat-tree>
.example-tree-invisible {
display: none;
}
.example-tree ul,
.example-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
/* This padding sets alignment of the nested nodes. */
.example-tree .mat-nested-tree-node div[role="group"] {
padding-left: 40px;
}
.example-tree div[role="group"] > .mat-tree-node {
padding-left: 40px;
}
h1,
h3 {
color: green;
font-family: "Roboto", sans-serif;
text-align: left;
}
.mat-tree {
background: transparent;
}
.mat-tree-node {
color: black;
}
<app-nested-tree-example> </app-nested-tree-example>
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
import { BrowserAnimationsModule }
from "@angular/platform-browser/animations";
import { NestedTreeExampleComponent }
from "./nested-tree-example/nested-tree-example.component";
import { MatTreeModule } from "@angular/material/tree";
import { MatIconModule } from "@angular/material/icon";
@NgModule({
declarations: [AppComponent, NestedTreeExampleComponent],
exports: [AppComponent],
imports: [
CommonModule,
BrowserAnimationsModule,
BrowserModule,
MatTreeModule,
MatIconModule,
],
bootstrap: [AppComponent],
})
export class AppModule {}
输出:
嵌套树实例