zoukankan      html  css  js  c++  java
  • Angular递归组件解决多级数据结构问题

    Angular递归组件解决多级数据结构问题

    前言

    在碰到树状结构的数据渲染时,往往层级的深度是不确定的,遇到这些问题,通常是用到了递归的方法去解决这些问题,而相对于一个组件来说,就可以通俗的说成递归组件。

    1、数据结构如下

    [
      {
        "id": 1,
        "name": "总公司",
        "parentid": 0,
        "order": 100000000,
        "checked": true,
        "level": 1,
        "expanded": false,
        "children": [
          {
            "id": 2,
            "name": "线上直销",
            "parentid": 1,
            "order": 100000000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 3,
            "name": "线下直销",
            "parentid": 1,
            "order": 99999000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 4,
            "name": "客服",
            "parentid": 1,
            "order": 99998000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 5,
            "name": "渠道",
            "parentid": 1,
            "order": 99997000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 6,
            "name": "产品",
            "parentid": 1,
            "order": 99996000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 7,
            "name": "技术",
            "parentid": 1,
            "order": 99995000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": [
              {
                "id": 12,
                "name": "测试",
                "parentid": 7,
                "order": 100000000,
                "checked": 0,
                "level": 3,
                "expanded": false,
                "children": []
              },
              {
                "id": 13,
                "name": "开发",
                "parentid": 7,
                "order": 99999000,
                "checked": 0,
                "level": 3,
                "expanded": false,
                "children": []
              },
              {
                "id": 14,
                "name": "测试很长的名称显示",
                "parentid": 7,
                "order": 99998000,
                "checked": 0,
                "level": 3,
                "expanded": false,
                "children": [
                  {
                    "id": 15,
                    "name": "测试很长的名称显示2",
                    "parentid": 14,
                    "order": 100000000,
                    "checked": 0,
                    "level": 4,
                    "expanded": false,
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": 8,
            "name": "运营",
            "parentid": 1,
            "order": 99994000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 9,
            "name": "市场推广",
            "parentid": 1,
            "order": 99993000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 10,
            "name": "讲师",
            "parentid": 1,
            "order": 99992000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          },
          {
            "id": 11,
            "name": "商务",
            "parentid": 1,
            "order": 99991000,
            "checked": 0,
            "level": 2,
            "expanded": false,
            "children": []
          }
        ]
      }
    ]
    

    2、使用递归组件去递归数据并且展示

    观察我们可以发现,每一条数据的结构都是一样的,有下级的关系children字段是有值的,因此书写一个结点组件department-tree-node

    当我们有子结点的时候,递归department-tree-node组件去实现数据的展示。

    <div class="department-tree-node">
      <div class="tree-node-wrap" *ngFor="let item of nodes">
        <div class="directory-wrap" [style.marginLeft]="item.children && item.children.length ? '0px' : '12px'">
          <i class="anticon anticon-caret-right close"
             *ngIf="item.children && item.children.length && !item.expanded"
             (click)="toggleExpand(item)">
          </i>
          <i class="anticon anticon-caret-down expand"
             *ngIf="item.children && item.children && item.expanded"
             (click)="toggleExpand(item)">
          </i>
          <p class="title-wrap" [class.checked]="item.checked" (click)="selectedGroup(item)">
            <i class="anticon anticon-folder"></i>
            <span class="title">{{ item.name }}</span>
          </p>
        </div>
       	
        <ng-container *ngIf="item.children && item.children.length">
          <div class="child-directory-wrap" [hidden]="!item.expanded">
            <department-tree-node [nodes]="item.children"></department-tree-node>
          </div>
        </ng-container>
      </div>
    </div>
    

    3、递归组件数据管理

    因为递归组件中,数据并非全部都在一个组件的属性变量里头,我们通常需要在组件初始化的时候去把这个组件给保存起来,以便后续去管理对应组件中的对应数据。如我们传入的Input为结点nodes数据,我们需要在点击一个子结点的时候去选中这个结点,并且给上class="checked"的样式,然后要把其他选中的结点给取消这个状态。这时我们访问this.nodes的时候,只有传入的nodes数据,并非全部的数据,因为所有的组件都是单例的,this指向都是指向当前的实例,因此this.nodes只是访问当前实例中的nodes这个数据而已,为了解决这个问题,我们可以在ngOnint这个生命周期里面,在模块中注入一个模块级别的service以便存入当前的组件实例。

    /**
     * @file 解决递归组件 实例指向问题 用service直接穿透
     */
    
    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs';
    
    @Injectable()
    export class MemberService {
      // 各个递归组件的实例
      public nodesInstance = [];
    }
    
    
    /**
     * @file 部门树形结构
     */
    
    import { Component, Input, OnInit } from '@angular/core';
    import { MemberService } from '../../member.service';
    
    @Component({
      selector: 'department-tree-node',
      templateUrl: './department-tree-node.component.html',
      styleUrls: ['./department-tree-node.component.scss']
    })
    
    export class DepartmentTreeNodeComponent implements OnInit {
    
      @Input()
      public nodes = [];
    
      constructor(
        public memberService: MemberService
      ) { }
    
      public ngOnInit() {
        // 将每一个组件的实例存储
        this.memberService.nodesInstance.push(this);
      }
    
      public toggleExpand(item: any) {
        item.expanded = !item.expanded;
      }
    
      public selectedGroup(item: any) {
        // 遍历组件实例中的结点数据nodes
        this.memberService.nodesInstance.forEach((instance: DepartmentTreeNodeComponent) => {
          instance.toggleChecked(instance, instance.nodes);
        });
        item.checked = true;
        this.memberService.departmentIdBehaviorSubject.next(item.id);
      }
    
      public toggleChecked(instance: DepartmentTreeNodeComponent, nodes: Array<object>) {
        nodes.forEach((item: any) => {
          item.checked = false;
          if (item.children && item.children.length) {
            instance.toggleChecked(instance, item.children);
          }
        });
      }
    }
    
    

    4、总结

    1. 观察数据结构,找出相同的数据结构,以便递归处理。
    2. 利用递归组件去递归数据并且展示。
    3. 用一个顶层的变量去存储当前递归组件的实例。
    4. 拿到各个实例,从而进行操作。
  • 相关阅读:
    leetcode 152. 乘积最大子序列
    leetcode 258. 各位相加 (python)
    leetcode 89. 格雷编码
    leetcode 62. 不同路径(C++)
    leetcode 142. 环形链表 II(c++)
    https证书制作及springboot配置https
    SpringBoot RestTemplate接收文件,并将文件发送到另外一个程序进行存储
    批量停止、删除docker容器
    记录Redis连接未正确释放,TCP连接过多,造成服务器上部分功能不可用和linux服务器内存一直增加问题
    外部连接mysql docker容器异常
  • 原文地址:https://www.cnblogs.com/chenfengami/p/13180960.html
Copyright © 2011-2022 走看看