import { Component, OnInit,Injectable } from '@angular/core';
import {CollectionViewer, SelectionChange, DataSource} from '@angular/cdk/collections';//定义和操作数据源(DataSource)和视图容器(CollectionViewer)以及选择状态的变化(SelectionChange)
import {FlatTreeControl} from '@angular/cdk/tree';//管理扁平节点的展开和折叠状态
import {BehaviorSubject, merge, Observable} from 'rxjs';//创建可观察对象和处理异步数据流
import {map} from 'rxjs/operators';// 从 RxJS 库中导入 map 操作符,用于对可观察对象发出的值进行转换。
// 树组件
export class DynamicFlatNode {//定义了一个 DynamicFlatNode 类,表示一个扁平节点(Flat node),包含可展开状态和层级信息
constructor(
public item: string,
public level = 1,
public expandable = false,
public isLoading = false,
) {}
}
@Injectable({providedIn: 'root'})//提供服务的装饰器语法。它的作用是将这个服务注册为根注入器的提供者。
export class DynamicDatabase {
dataMap = new Map<string, string[]>([//定义了一个名为 dataMap 的 Map 对象,用于存储树形结构的数据
['Fruits', ['Apple', 'Orange', 'Banana']],
['Vegetables', ['Tomato', 'Potato', 'Onion']],
['Apple', ['Fuji', 'Macintosh']],
['Onion', ['Yellow', 'White', 'Purple']],
]);
rootLevelNodes: string[] = ['Fruits', 'Vegetables'];//定义了一个名为 rootLevelNodes 的数组,其中包含了根节点的名称
initialData(): DynamicFlatNode[] {//定义了一个名为 initialData 的方法,用于返回初始的树节点数据。在这个方法中,通过遍历 rootLevelNodes 数组创建了一个 DynamicFlatNode 对象的数组,并将其作为初始数据返回。
return this.rootLevelNodes.map(name => new DynamicFlatNode(name, 0, true));
}
getChildren(node: string): string[] | undefined {//定义了一个名为 getChildren 的方法,用于获取指定节点的子节点数组。在这个方法中,通过调用 dataMap.get(node) 方法获取指定节点的子节点数组,并返回结果
return this.dataMap.get(node);
}
isExpandable(node: string): boolean {//定义了一个名为 isExpandable 的方法,用于判断指定节点是否可展开(即是否有子节点)。在这个方法中,通过调用 dataMap.has(node) 方法判断指定节点是否存在于 dataMap 中,若存在则说明该节点有子节点,返回 true,否则返回 false。
return this.dataMap.has(node);
}
}
export class DynamicDataSource implements DataSource<DynamicFlatNode> {// 定义了一个名为 DynamicDataSource 的类,它实现了 DataSource 接口,这个接口的泛型参数指定为 DynamicFlatNode,表示这个数据源提供的是 DynamicFlatNode 类型的数据。
dataChange = new BehaviorSubject<DynamicFlatNode[]>([]);//定义了一个名为 dataChange 的 BehaviorSubject 对象,用于在数据发生变化时向订阅者(subscribers)发送通
get data(): DynamicFlatNode[] {//定义了一个名为 data 的 getter 方法,用于获取树形结构的数据。在这个方法中,通过访问 dataChange 的值来获取当前的树形结构数据。
return this.dataChange.value;
}
set data(value: DynamicFlatNode[]) {//定义了一个名为 data 的 setter 方法,用于设置树形结构的数据。在这个方法中,首先将传入的新数据赋值给 _treeControl.dataNodes 属性,然后通过调用 dataChange.next() 方法发射新的数据,以通知所有订阅者更新数据。
this._treeControl.dataNodes = value;
this.dataChange.next(value);
}
constructor(// 定义了一个构造函数,接受两个参数 _treeControl 和 _database,分别表示 TreeControl 对象和数据源对象。在这个构造函数中,将接收到的 _treeControl 对象赋值给组件的 _treeControl 属性,将接收到的 _database 对象赋值给私有属性 _database。
private _treeControl: FlatTreeControl<DynamicFlatNode>,
private _database: DynamicDatabase,
) {}
// 实现 DataSource 接口中的 connect() 和 disconnect() 方法
connect(collectionViewer: CollectionViewer): Observable<DynamicFlatNode[]> {// DataSource 接口中的 connect() 方法,这个方法返回一个 Observable 对象,它用于向 TreeControl 提供数据。
this._treeControl.expansionModel.changed.subscribe(change => {
if (
(change as SelectionChange<DynamicFlatNode>).added ||
(change as SelectionChange<DynamicFlatNode>).removed
) {
this.handleTreeControl(change as SelectionChange<DynamicFlatNode>);
}
});
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
}
disconnect(collectionViewer: CollectionViewer): void {}// DataSource 接口中的 disconnect() 方法,这个方法在数据源不再需要使用时被调用,可以在这个方法中清理资源。
handleTreeControl(change: SelectionChange<DynamicFlatNode>) {// Tree中的一个方法,用于处理树形结构的控制变化
if (change.added) {
change.added.forEach(node => this.toggleNode(node, true));
}
if (change.removed) {
change.removed
.slice()
.reverse()
.forEach(node => this.toggleNode(node, false));
}
}
toggleNode(node: DynamicFlatNode, expand: boolean) {// Tree中的一个方法,用于展开或关闭树形结构中的一个节点
const children = this._database.getChildren(node.item);
const index = this.data.indexOf(node);
if (!children || index < 0) {
// If no children, or cannot find the node, no op
return;
}
node.isLoading = true;
setTimeout(() => {//使用 setTimeout() 方法模拟异步加载,等待 1 秒钟后执行回调函数。在回调函数中,根据需要展开还是关闭节点,进行不同的操作
if (expand) {
const nodes = children.map(
name => new DynamicFlatNode(name, node.level + 1, this._database.isExpandable(name)),
);
this.data.splice(index + 1, 0, ...nodes);
} else {
let count = 0;
for (
let i = index + 1;
i < this.data.length && this.data[i].level > node.level;
i++, count++
) {}
this.data.splice(index + 1, count);
}
// notify the change
this.dataChange.next(this.data);
node.isLoading = false;
}, 1000);
}
}
@Component({
selector: 'app-dynamic-tree-demo',
templateUrl: './dynamic-tree-demo.component.html',
styleUrls: ['./dynamic-tree-demo.component.scss']
})//定义组件的装饰器要 紧挨着组件ts 要不要报错
export class DynamicTreeDemoComponent implements OnInit {
constructor(database: DynamicDatabase) {
this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
this.dataSource = new DynamicDataSource(this.treeControl, database);
this.dataSource.data = database.initialData();
}
treeControl: FlatTreeControl<DynamicFlatNode>;//表示树形结构的控制器对象,用于管理树形结构的展开和闭合。
dataSource: DynamicDataSource;//表示树形结构的数据源对象,用于管理树形结构的数据加载。
getLevel = (node: DynamicFlatNode) => node.level;//一个箭头函数,用于获取节点的级别。
isExpandable = (node: DynamicFlatNode) => node.expandable;//箭头函数,用于判断节点是否可展开。
hasChild = (_: number, _nodeData: DynamicFlatNode) => _nodeData.expandable;//函数,用于判断节点是否有子节点。
ngOnInit(): void {
}
}
angular material tree 动态加载子项有注释的ts
最新推荐文章于 2024-05-17 13:52:13 发布