Angular Material 平面树父子图形表示
Angular Material Flat Tree Parent Children Graphical Representaion
我想在 Angular Material Flat Tree 上显示父子图形表示。
这是设计:
Here is the DEMO what i done so far.
第一个解
这里是 stackBlitz Demo
我使用 treeControl.dataNodes.indexOf(node)
对引用节点索引的每个可见节点进行了递归调用
这里是递归函数:
recNode( arr:any[], data:any[], index:number, maxIndex:number ):any[] {
if ( arr === undefined )
arr = [];
for ( let i = 0; i < data.length; i++ ) {
index++
if ( index === maxIndex ) return ( [ true, index, arr ] );
if ( data[i].children.length ) {
let res = this.recNode( arr, data[i].children, index, maxIndex )
index = res[1];
if ( res[0] === true ) {
arr.splice( 0, 0, ( i !== ( data.length - 1 ) ) )
return ( [ true, index, arr ] );
}
}
}
return ( [ false, index, arr ] );
}
这个 returns true
false
值的数组 [ngClass]
然后在 html 中我这样调用该函数
<li *ngFor="let r of recNode( undefined, dataSource.data, -1, treeControl.dataNodes.indexOf( node ) )[2]; [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>
最后,我在 css 中创建了另一个 class,名为 node-arrow-empty
无边框
.node-arrow-nox {
position: relative;
// min-width: 48px;
// min-height: 48px;
.node-arrow {
position: relative;
min-width: 48px;
min-height: 48px;
&:before {
content: "";
position: absolute;
top: -20px;
left: 20px;
border-left: 1px solid $copounsCount;
bottom: 0;
}
}
.node-arrow-empty {
position: relative;
min-width: 48px;
min-height: 48px;
&:before {
content: "";
position: absolute;
top: -20px;
left: 20px;
bottom: 0;
}
}
}
根据数组中的值是 true
还是 false
,它会在两个 class 之间切换 html。
第二种解决方案
另一个解决方案是通过添加例如 isLast:boolean
属性 来跟踪数组中的最后一个元素。当然,如果您处理的数据是动态的,您需要找到一种动态更改该值的方法。
一旦 isLast
被填满,您将进行递归调用,它将找到前一个具有 current node level - 1
的同级。话虽这么说,你会检查两件事。第一件事是,节点 classes 是否包含 n-last
(这是我给 Html 的 class 名称,代表父数组的最后一个元素),第二件事检索 class n-{{node-level}}
.
通过递归(如果你不想的话,你可以创建一个非递归方法)检索具有 class n-3
或 n-2
的 previousElementSibling
...到 n-0
你可以检查每个元素是否包含一个 n-last
class。您将 true
或 false
推入数组,就像第一个解决方案在 class node-arrow
和 node-arrow-empty
.
之间切换一样
这里是递归函数
dummy( el:any, arr:any[], level:number ) {
let classes = el.className;
if ( arr === undefined )
arr = [];
else {
arr.splice( 0, 0, classes.includes( 'n-last' ) );
}
let np = /(?!n-)\d+/g;
let m = classes.match( np );
let nLevel = parseInt( m[0] );
nLevel--;
if ( nLevel < 0 ) return ( arr );
while ( parseInt( el.className.match( np )[0] ) !== nLevel ) {
el = el.previousElementSibling;
}
arr = this.dummy(el, arr, nLevel);
return (arr);
}
HTML(这里只有父节点,子节点也一样)
<mat-tree-node #refP class="parent-node {{'n-' + node.level}} " *matTreeNodeDef="let node; when: grpNode;" matTreeNodePadding matTreeNodePaddingIndent="0" cdkDrag [cdkDragData]="node" [ngClass]="{'no-child': !node.children.length, 'n-last': node.isLast}">
<span class="node-arrow-nox d-flex">
<li [ngClass]="{'node-arrow': !r , 'node-arrow-empty': r}" *ngFor="let r of dummy(refP, undefined, node.level)"></li>
</span>
<button class="node-toggle" mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.filename" [disabled]="!node.children.length">
<mat-icon class="mat-icon-rtl-mirror toggle-arrow">
{{treeControl.isExpanded(node) ? 'play_arrow' : 'play_arrow'}}
</mat-icon>
</button>
<div class="node-icon icon-h-arw"></div>
<div class="node-name">{{node.isLast}}-{{node.accntCode}} <span>: :</span> {{node.name}} </div>
</mat-tree-node>
如您所见,我使用名为 #refP
的模板变量将元素传递给虚拟函数
这里是 PARENTNODE
和 CHILDNODE
声明:
export class PARENTNODE {
id: string;
isLast: boolean;
...
actAsSupplier: boolean;
}
/* Flat node with expandable and level information */
export class CHILDNODE {
constructor(
public id: string,
public isLast: boolean,
...
public actAsSupplier: boolean,
){}
}
第三种解法
我不会编写代码,但我会尝试解释它。
这有点类似于之前的解决方案,除了您可以在树更改(交换、删除、添加)数据时解析并添加一个 属性,例如 divType
填充 [=18] =] 或 false
并在你的 html 中调用它
<li *ngFor="let r of node.divType" [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>
我想在 Angular Material Flat Tree 上显示父子图形表示。
这是设计:
Here is the DEMO what i done so far.
第一个解
这里是 stackBlitz Demo
我使用 treeControl.dataNodes.indexOf(node)
这里是递归函数:
recNode( arr:any[], data:any[], index:number, maxIndex:number ):any[] {
if ( arr === undefined )
arr = [];
for ( let i = 0; i < data.length; i++ ) {
index++
if ( index === maxIndex ) return ( [ true, index, arr ] );
if ( data[i].children.length ) {
let res = this.recNode( arr, data[i].children, index, maxIndex )
index = res[1];
if ( res[0] === true ) {
arr.splice( 0, 0, ( i !== ( data.length - 1 ) ) )
return ( [ true, index, arr ] );
}
}
}
return ( [ false, index, arr ] );
}
这个 returns true
false
值的数组 [ngClass]
然后在 html 中我这样调用该函数
<li *ngFor="let r of recNode( undefined, dataSource.data, -1, treeControl.dataNodes.indexOf( node ) )[2]; [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>
最后,我在 css 中创建了另一个 class,名为 node-arrow-empty
无边框
.node-arrow-nox {
position: relative;
// min-width: 48px;
// min-height: 48px;
.node-arrow {
position: relative;
min-width: 48px;
min-height: 48px;
&:before {
content: "";
position: absolute;
top: -20px;
left: 20px;
border-left: 1px solid $copounsCount;
bottom: 0;
}
}
.node-arrow-empty {
position: relative;
min-width: 48px;
min-height: 48px;
&:before {
content: "";
position: absolute;
top: -20px;
left: 20px;
bottom: 0;
}
}
}
根据数组中的值是 true
还是 false
,它会在两个 class 之间切换 html。
第二种解决方案
另一个解决方案是通过添加例如 isLast:boolean
属性 来跟踪数组中的最后一个元素。当然,如果您处理的数据是动态的,您需要找到一种动态更改该值的方法。
一旦 isLast
被填满,您将进行递归调用,它将找到前一个具有 current node level - 1
的同级。话虽这么说,你会检查两件事。第一件事是,节点 classes 是否包含 n-last
(这是我给 Html 的 class 名称,代表父数组的最后一个元素),第二件事检索 class n-{{node-level}}
.
通过递归(如果你不想的话,你可以创建一个非递归方法)检索具有 class n-3
或 n-2
的 previousElementSibling
...到 n-0
你可以检查每个元素是否包含一个 n-last
class。您将 true
或 false
推入数组,就像第一个解决方案在 class node-arrow
和 node-arrow-empty
.
这里是递归函数
dummy( el:any, arr:any[], level:number ) {
let classes = el.className;
if ( arr === undefined )
arr = [];
else {
arr.splice( 0, 0, classes.includes( 'n-last' ) );
}
let np = /(?!n-)\d+/g;
let m = classes.match( np );
let nLevel = parseInt( m[0] );
nLevel--;
if ( nLevel < 0 ) return ( arr );
while ( parseInt( el.className.match( np )[0] ) !== nLevel ) {
el = el.previousElementSibling;
}
arr = this.dummy(el, arr, nLevel);
return (arr);
}
HTML(这里只有父节点,子节点也一样)
<mat-tree-node #refP class="parent-node {{'n-' + node.level}} " *matTreeNodeDef="let node; when: grpNode;" matTreeNodePadding matTreeNodePaddingIndent="0" cdkDrag [cdkDragData]="node" [ngClass]="{'no-child': !node.children.length, 'n-last': node.isLast}">
<span class="node-arrow-nox d-flex">
<li [ngClass]="{'node-arrow': !r , 'node-arrow-empty': r}" *ngFor="let r of dummy(refP, undefined, node.level)"></li>
</span>
<button class="node-toggle" mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.filename" [disabled]="!node.children.length">
<mat-icon class="mat-icon-rtl-mirror toggle-arrow">
{{treeControl.isExpanded(node) ? 'play_arrow' : 'play_arrow'}}
</mat-icon>
</button>
<div class="node-icon icon-h-arw"></div>
<div class="node-name">{{node.isLast}}-{{node.accntCode}} <span>: :</span> {{node.name}} </div>
</mat-tree-node>
如您所见,我使用名为 #refP
这里是 PARENTNODE
和 CHILDNODE
声明:
export class PARENTNODE {
id: string;
isLast: boolean;
...
actAsSupplier: boolean;
}
/* Flat node with expandable and level information */
export class CHILDNODE {
constructor(
public id: string,
public isLast: boolean,
...
public actAsSupplier: boolean,
){}
}
第三种解法
我不会编写代码,但我会尝试解释它。
这有点类似于之前的解决方案,除了您可以在树更改(交换、删除、添加)数据时解析并添加一个 属性,例如 divType
填充 [=18] =] 或 false
并在你的 html 中调用它
<li *ngFor="let r of node.divType" [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>