6

我想在 Angular Material Flat Tree 上显示父子图形表示。

这是设计:

在此处输入图像描述

这是我到目前为止所做的演示。

4

1 回答 1

6

第一个解决方案

这是stackBlitz 演示

这是stackBlitz 可编辑链接

我已经使用递归调用了每个可见节点引用节点索引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 ] );

  }

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中创建了另一个类,称为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它在两个类之间的 html 中切换。

第二个解决方案

stackBlitz 演示

stackBlitz 可编辑链接

isLast:boolean另一种解决方案是通过添加例如属性来跟踪数组中的最后一个元素。当然,如果您正在处理的数据是动态的,您需要找到一种方法来动态地更改该值。

一旦isLast被填充,您将进行递归调用,它将找到前一个兄弟姐妹current node level - 1。话虽如此,您将检查两件事。首先是节点类包含n-last(这是我给 Html 的类名,表示父数组的最后一个元素),第二件事是检索类n-{{node-level}}

通过递归(如果你不想这样做,你可以创建一个非递归方法)检索previousElementSiblingwhich has class n-3or n-2...n-0你可以检查每个元素是否包含一个n-last类。您将trueor推false入一个数组,就像第一个解决方案在 classnode-arrownode-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

这是PARENTNODECHILDNODE声明:

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填充trueorfalse并在您的 html 中调用它

 <li *ngFor="let r of node.divType" [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>
于 2019-10-05T13:03:41.870 回答