Skip to content

Commit

Permalink
feat(module:tree): support virtual scroll (#4979)
Browse files Browse the repository at this point in the history
close #4426 close #3808 close #3436 close #2680 close #1771
  • Loading branch information
Yadong Xie committed Apr 4, 2020
1 parent cdf387f commit 6803a92
Show file tree
Hide file tree
Showing 25 changed files with 1,376 additions and 1,112 deletions.
1 change: 0 additions & 1 deletion components/core/tree/nz-tree-base-node.ts
Expand Up @@ -387,7 +387,6 @@ export class NzTreeNode {

public update(): void {
if (this.component) {
this.component.setClassMap();
this.component.markForCheck();
}
}
Expand Down
1 change: 1 addition & 0 deletions components/core/tree/nz-tree-base-util.ts
Expand Up @@ -46,6 +46,7 @@ export function flattenTreeData(treeNodeList: NzTreeNode[] = [], expandedKeys: N
treeNode.isStart = [...(parent ? parent.isStart : []), index === 0];
treeNode.isEnd = [...(parent ? parent.isEnd : []), index === list.length - 1];
// Add FlattenDataNode into list
// TODO: only need data here.
const flattenNode: FlattenNode = {
parent,
pos,
Expand Down
1 change: 0 additions & 1 deletion components/core/tree/nz-tree-base.definitions.ts
Expand Up @@ -27,6 +27,5 @@ export interface NzFormatBeforeDropEvent {
}

export interface NzTreeNodeBaseComponent {
setClassMap(): void;
markForCheck(): void;
}
7 changes: 4 additions & 3 deletions components/core/tree/nz-tree-base.service.ts
Expand Up @@ -9,7 +9,8 @@
import { Injectable } from '@angular/core';

import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { FlattenNode, NzTreeNode, NzTreeNodeKey } from './nz-tree-base-node';
import { BehaviorSubject } from 'rxjs';
import { NzTreeNode, NzTreeNodeKey } from './nz-tree-base-node';
import { flattenTreeData, isCheckDisabled, isInArray } from './nz-tree-base-util';
import { NzFormatEmitEvent } from './nz-tree-base.definitions';

Expand All @@ -22,7 +23,7 @@ export class NzTreeBaseService {
isMultiple: boolean = false;
selectedNode: NzTreeNode;
rootNodes: NzTreeNode[] = [];
flattenNodes: FlattenNode[] = [];
flattenNodes$ = new BehaviorSubject<NzTreeNode[]>([]);
selectedNodeList: NzTreeNode[] = [];
expandedNodeList: NzTreeNode[] = [];
checkedNodeList: NzTreeNode[] = [];
Expand All @@ -42,7 +43,7 @@ export class NzTreeBaseService {
}

flattenTreeData(nzNodes: NzTreeNode[], expandedKeys: NzTreeNodeKey[] | true = []): void {
this.flattenNodes = flattenTreeData(nzNodes, expandedKeys);
this.flattenNodes$.next(flattenTreeData(nzNodes, expandedKeys).map(item => item.data));
}

getSelectedNode(): NzTreeNode | null {
Expand Down
19 changes: 5 additions & 14 deletions components/tree/demo/customized-icon.ts
Expand Up @@ -3,20 +3,11 @@ import { Component } from '@angular/core';
@Component({
selector: 'nz-demo-tree-customized-icon',
template: `
<nz-tree [nzData]="nodes" nzShowIcon [nzExpandedIcon]="expandedIconTpl">
<ng-template #expandedIconTpl let-node>
<i nz-icon [nzType]="node.origin.icon" class="ant-tree-switcher-icon"></i>
</ng-template>
</nz-tree>
<nz-tree [nzData]="nodes" nzShowIcon [nzExpandedIcon]="mutiExpandedIconTpl">
<ng-template #mutiExpandedIconTpl let-node>
<i
*ngIf="!node.origin.isLeaf"
nz-icon
[nzType]="node.isExpanded ? 'folder-open' : 'folder'"
class="ant-tree-switcher-line-icon"
></i>
<i *ngIf="node.origin.isLeaf" nz-icon nzType="file" class="ant-tree-switcher-line-icon"></i>
<nz-tree [nzData]="nodes" nzShowIcon></nz-tree>
<nz-tree [nzData]="nodes" nzShowIcon [nzExpandedIcon]="multiExpandedIconTpl">
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<i *ngIf="!origin.isLeaf" nz-icon [nzType]="node.isExpanded ? 'folder-open' : 'folder'" class="ant-tree-switcher-line-icon"></i>
<i *ngIf="origin.isLeaf" nz-icon nzType="file" class="ant-tree-switcher-line-icon"></i>
</ng-template>
</nz-tree>
`
Expand Down
4 changes: 2 additions & 2 deletions components/tree/demo/directory.md
Expand Up @@ -7,8 +7,8 @@ title:

## zh-CN

自定义目录树(使用 `nzTreeTemplate` 实现,支持右键)
使用 `nzTreeTemplate` 实现自定义目录结构,通过 `let-origin="origin"` 获得原始数据,`let-node` 获取当前节点状态

## en-US

Customize directory tree(with `nzTreeTemplate`, supported contextmenu).
Customize directory tree with `nzTreeTemplate`, get data from `let-origin="origin"`, get node status from `let-node`.
16 changes: 6 additions & 10 deletions components/tree/demo/directory.ts
Expand Up @@ -12,7 +12,7 @@ import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dro
(nzDblClick)="openFolder($event)"
[nzTreeTemplate]="nzTreeTemplate"
></nz-tree>
<ng-template #nzTreeTemplate let-node let-origin>
<ng-template #nzTreeTemplate let-node let-origin="origin">
<span class="custom-node">
<span *ngIf="!node.isLeaf" (contextmenu)="contextMenu($event, menu)">
<i nz-icon [nzType]="node.isExpanded ? 'folder-open' : 'folder'" (click)="openFolder(node)"></i>
Expand All @@ -35,16 +35,12 @@ import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dro
`,
styles: [
`
:host ::ng-deep .ant-tree {
nz-tree {
overflow: hidden;
margin: 0 -24px;
padding: 0 24px;
}
:host ::ng-deep .ant-tree li {
padding: 4px 0 0 0;
}
.custom-node {
cursor: pointer;
line-height: 24px;
Expand All @@ -70,8 +66,8 @@ import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dro
]
})
export class NzDemoTreeDirectoryComponent {
// actived node
activedNode: NzTreeNode;
// activated node
activatedNode: NzTreeNode;
nodes = [
{
title: 'parent 0',
Expand All @@ -94,7 +90,7 @@ export class NzDemoTreeDirectoryComponent {
}
];

openFolder(data: NzTreeNode | Required<NzFormatEmitEvent>): void {
openFolder(data: NzTreeNode | NzFormatEmitEvent): void {
// do something if u want
if (data instanceof NzTreeNode) {
data.isExpanded = !data.isExpanded;
Expand All @@ -107,7 +103,7 @@ export class NzDemoTreeDirectoryComponent {
}

activeNode(data: NzFormatEmitEvent): void {
this.activedNode = data.node!;
this.activatedNode = data.node!;
}

contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
Expand Down
14 changes: 14 additions & 0 deletions components/tree/demo/virtual-scroll.md
@@ -0,0 +1,14 @@
---
order: 8
title:
zh-CN: 虚拟滚动
en-US: Virtual Scroll
---

## zh-CN

设定 `nzVirtualHeight` 开启虚拟滚动。

## en-US

Set `nzVirtualHeight` to enable virtual scroll.
36 changes: 36 additions & 0 deletions components/tree/demo/virtual-scroll.ts
@@ -0,0 +1,36 @@
import { Component, OnInit } from '@angular/core';
import { NzTreeNodeOptions } from 'ng-zorro-antd';

@Component({
selector: 'nz-demo-tree-virtual-scroll',
template: ` <nz-tree [nzData]="nodes" nzBlockNode nzVirtualHeight="300px"></nz-tree> `
})
export class NzDemoTreeVirtualScrollComponent implements OnInit {
nodes: NzTreeNodeOptions[] = [];
ngOnInit(): void {
const dig = (path = '0', level = 3) => {
const list = [];
for (let i = 0; i < 10; i += 1) {
const key = `${path}-${i}`;
const treeNode: NzTreeNodeOptions = {
title: key,
key,
expanded: true,
children: [],
isLeaf: false
};

if (level > 0) {
treeNode.children = dig(key, level - 1);
} else {
treeNode.isLeaf = true;
}

list.push(treeNode);
}
return list;
};

this.nodes = dig();
}
}
4 changes: 4 additions & 0 deletions components/tree/doc/index.en-US.md
Expand Up @@ -38,6 +38,10 @@ import { NzTreeModule } from 'ng-zorro-antd/tree';
| `[nzSearchValue]` | Filter (highlight) treeNodes (see demo `Searchable`), two-way binding | `string` | `null` |
| `[nzSearchFunc]` | Custom matching method, used with nzSearchValue | `(node: NzTreeNodeOptions) => boolean` | `null` |
| `[nzBeforeDrop]` | Drop before the second check, allowing the user to decide whether to allow placement | `(confirm: NzFormatBeforeDropEvent) => Observable<boolean>` | - |
| `[nzVirtualHeight]` | The height of virtual scroll | `string` | `-` |
| `[nzVirtualItemSize]` | The size of the items in the list, same as [cdk itemSize](https://material.angular.io/cdk/scrolling/api) | `number` | `0` |
| `[nzVirtualMaxBufferPx]` | The number of pixels worth of buffer to render for when rendering new items, same as [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) | `number` | `200` |
| `[nzVirtualMinBufferPx]` | The minimum amount of buffer rendered beyond the viewport (in pixels),same as [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api) | `number` | `100` |
| `(nzClick)` | Callback function for when the user clicks a treeNode | `EventEmitter<NzFormatEmitEvent>` | - |
| `(nzDblClick)` | Callback function for when the user double clicks a treeNode | `EventEmitter<NzFormatEmitEvent>` | - |
| `(nzContextMenu)` | Callback function for when the user right clicks a treeNode | `EventEmitter<NzFormatEmitEvent>` | - |
Expand Down
4 changes: 4 additions & 0 deletions components/tree/doc/index.zh-CN.md
Expand Up @@ -39,6 +39,10 @@ import { NzTreeModule } from 'ng-zorro-antd/tree';
| `[nzSearchValue]` | 按需筛选树高亮节点(参考可搜索的树),双向绑定 | `string` | `null` |
| `[nzSearchFunc]` | 自定义匹配方法,配合 nzSearchValue 使用 | `(node: NzTreeNodeOptions) => boolean` | `null` |
| `[nzBeforeDrop]` | drop前二次校验,允许用户自行决定是否允许放置 | `(confirm: NzFormatBeforeDropEvent) => Observable<boolean>` | - |
| `[nzVirtualHeight]` | 虚拟滚动的总高度 | `string` | `-` |
| `[nzVirtualItemSize]` | 虚拟滚动时每一列的高度,与 [cdk itemSize](https://material.angular.io/cdk/scrolling/api) 相同 | `number` | `0` |
| `[nzVirtualMaxBufferPx]` | 缓冲区最大像素高度,与 [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) 相同 | `number` | `200` |
| `[nzVirtualMinBufferPx]` | 缓冲区最小像素高度,低于该值时将加载新结构,与 [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api) 相同 | `number` | `100` |
| `(nzClick)` | 点击树节点触发 | `EventEmitter<NzFormatEmitEvent>` | - |
| `(nzDblClick)` | 双击树节点触发 | `EventEmitter<NzFormatEmitEvent>` | - |
| `(nzContextMenu)` | 右键树节点触发 | `EventEmitter<NzFormatEmitEvent>` | - |
Expand Down

0 comments on commit 6803a92

Please sign in to comment.