基于Material2的Tab实现

2017-11-28  本文已影响0人  环零弦

原始需求:

一个正常的Tab(有Tab的基本功能),Tab的内容基于Component。

具体功能描述:

具体实现:

问题一:

根据左侧的导航项,向右侧组件传值:

app-sidebar-nav.component.ts

import { Component, ElementRef, Input, OnInit, Renderer2 } from '@angular/core';

// Import navigation elements
import { navigation } from './../../_nav';
import { Router } from '@angular/router';
import { LocalStorage } from '../../providers/local.storage';
import { SubmitService } from '../../providers/submit.service';
import { FullLayoutComponent } from '../../containers/full-layout/full-layout.component';

@Component({
  selector: 'app-sidebar-nav',
  template: `
    <nav class="sidebar-nav">
      <ul class="nav">
        <ng-template ngFor let-navitem [ngForOf]="navObj">
          <li *ngIf="isDivider(navitem)" class="nav-divider"></li>
          <ng-template [ngIf]="isTitle(navitem)">
            <app-sidebar-nav-title [title]='navitem'></app-sidebar-nav-title>
          </ng-template>
          <ng-template [ngIf]="!isDivider(navitem)&&!isTitle(navitem)">
            <app-sidebar-nav-item [item]='navitem'></app-sidebar-nav-item>
          </ng-template>
        </ng-template>
      </ul>
    </nav>`
})
export class AppSidebarNavComponent implements OnInit {
  public navObj;
  private respData: string;
  private errorMessage: any;

  public isDivider(item) {
    return item.divider ? true : false
  }

  public isTitle(item) {
    return item.title ? true : false
  }

  constructor(private ls: LocalStorage) {
    // this.navObj = navigation;
  }
  ngOnInit() {
    const srcArray = navigation;
    const distArray = [];
    const privilegeCodeObj = this.ls.getObject('privilegeCode');
    for (let priviCodeLvlCount_1 = 0; priviCodeLvlCount_1 < srcArray.length; priviCodeLvlCount_1++) {
      if (srcArray[priviCodeLvlCount_1].privilegeCode === 'static') {
        distArray.push(srcArray[priviCodeLvlCount_1]);
      } else {
        if (privilegeCodeObj[srcArray[priviCodeLvlCount_1].privilegeCode]) {
          distArray.push(srcArray[priviCodeLvlCount_1]);
          const srcChildrenArray = srcArray[priviCodeLvlCount_1]['children'];
          const distChildrenArray = [];
          for (let priviCodeLvlCount_2 = 0; priviCodeLvlCount_2 < srcChildrenArray.length; priviCodeLvlCount_2++) {
            if (privilegeCodeObj[srcChildrenArray[priviCodeLvlCount_2].privilegeCode]) {
              distChildrenArray.push(srcChildrenArray[priviCodeLvlCount_2]);
            }
          }
          distArray[distArray.length - 1]['children'] = distChildrenArray;
        }
      }
    }
    this.navObj = distArray;
  }
}
@Component({
  selector: 'app-sidebar-nav-item',
  template: `
    <li *ngIf="!isDropdown(); else dropdown" [ngClass]="hasClass() ? 'nav-item ' + item.class : 'nav-item'">
      <app-sidebar-nav-link [link]='item'></app-sidebar-nav-link>
    </li>
    <ng-template #dropdown>
      <li [ngClass]="hasClass() ? 'nav-item nav-dropdown ' + item.class : 'nav-item nav-dropdown'"
          [class.open]="isActive()"
          routerLinkActive="open"
          appNavDropdown>
        <app-sidebar-nav-dropdown [link]='item'></app-sidebar-nav-dropdown>
      </li>
    </ng-template>
  `
})
export class AppSidebarNavItemComponent {
  @Input() item: any;

  public hasClass() {
    return this.item.class ? true : false
  }

  public isDropdown() {
    return this.item.children ? true : false
  }

  public thisUrl() {
    return this.item.url
  }

  public isActive() {
    return this.router.isActive(this.thisUrl(), false)
  }

  constructor(private router: Router) { }

}

@Component({
  selector: 'app-sidebar-nav-link',
  template: `
    <a *ngIf="!isExternalLink(); else external"
      [ngClass]="hasVariant() ? 'nav-link nav-link-' + link.variant : 'nav-link'"
      routerLinkActive="active"
      (click)="linkClick({path: link.url, label: link.name, code: link.privilegeCode})">
<!--       [routerLink]="[link.url]">-->
      <i *ngIf="isIcon()" class="{{ link.icon }}"></i>
      {{ link.name }}
      <span *ngIf="isBadge()" [ngClass]="'badge badge-' + link.badge.variant">{{ link.badge.text }}</span>
    </a>
    <ng-template #external>
      <a [ngClass]="hasVariant() ? 'nav-link nav-link-' + link.variant : 'nav-link'" href="{{link.url}}">
        <i *ngIf="isIcon()" class="{{ link.icon }}"></i>
        {{ link.name }}
        <span *ngIf="isBadge()" [ngClass]="'badge badge-' + link.badge.variant">{{ link.badge.text }}</span>
      </a>
    </ng-template>
  `
})
export class AppSidebarNavLinkComponent {
  @Input() link: any;

  public hasVariant() {
    return this.link.variant ? true : false
  }

  public isBadge() {
    return this.link.badge ? true : false
  }

  public isExternalLink() {
    return this.link.url.substring(0, 4) === 'http';
  }

  public isIcon() {
    return this.link.icon ? true : false
  }

  public linkClick(linkInfo) {
    this.fullLayoutComponent.updateArrays(linkInfo);
  }

  constructor(private fullLayoutComponent: FullLayoutComponent) { }
}

@Component({
  selector: 'app-sidebar-nav-dropdown',
  template: `
    <a class="nav-link nav-dropdown-toggle" appNavDropdownToggle href="#">
      <i *ngIf="isIcon()" class="{{ link.icon }}"></i>
      {{ link.name }}
      <span *ngIf="isBadge()" [ngClass]="'badge badge-' + link.badge.variant">{{ link.badge.text }}</span>
    </a>
    <ul class="nav-dropdown-items">
      <ng-template ngFor let-child [ngForOf]="link.children">
        <app-sidebar-nav-item [item]='child'></app-sidebar-nav-item>
      </ng-template>
    </ul>
  `
})
export class AppSidebarNavDropdownComponent {
  @Input() link: any;

  public isBadge() {
    return this.link.badge ? true : false
  }

  public isIcon() {
    return this.link.icon ? true : false
  }

  constructor() { }
}

@Component({
  selector: 'app-sidebar-nav-title',
  template: ''
})
export class AppSidebarNavTitleComponent implements OnInit {
  @Input() title: any;

  constructor(private el: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {
    const nativeElement: HTMLElement = this.el.nativeElement;
    const li = this.renderer.createElement('li');
    const name = this.renderer.createText(this.title.name);

    this.renderer.addClass(li, 'nav-title');

    if (this.title.class) {
      const classes = this.title.class;
      this.renderer.addClass(li, classes);
    }

    if (this.title.wrapper) {
      const wrapper = this.renderer.createElement(this.title.wrapper.element);

      this.renderer.appendChild(wrapper, name);
      this.renderer.appendChild(li, wrapper);
    } else {
      this.renderer.appendChild(li, name);
    }
    this.renderer.appendChild(nativeElement, li)
  }
}

export const APP_SIDEBAR_NAV = [
  AppSidebarNavComponent,
  AppSidebarNavDropdownComponent,
  AppSidebarNavItemComponent,
  AppSidebarNavLinkComponent,
  AppSidebarNavTitleComponent
];

根据左侧页面传值,打开Tab页,并加载组件(HTML部分):

full-layout.component.html

<app-header></app-header>
<div class="app-body">
  <app-sidebar></app-sidebar>
  <!-- Main content -->
  <main class="main">
    <!-- Breadcrumb -->
    <!--<ol class="breadcrumb">
          <app-breadcrumbs></app-breadcrumbs>
        </ol>-->
    <!--   routerLinkActive #rla="routerLinkActive"
        [active]="rla.isActive">-->
    <div>
      <nav mat-tab-nav-bar>
        <a mat-tab-link *ngFor="let link of navLinks" (click)="activeTabLabel(link.code)" [routerLink]="link.path" [active]="link.isActive">
          {{link.label}}
          <i class="fa fa-close fa-lg" style="margin: 2px 0px 0px 5px" (click)="closeTab(link.code)"></i>
        </a>
      </nav>
      <router-outlet></router-outlet>
    </div>
    <!-- /.conainer-fluid-------class="container-fluid"-->
  </main>
  <app-aside></app-aside>
</div>
<!--<app-footer></app-footer>-->

根据左侧页面传值,打开Tab页,并加载组件(TS部分):

full-layout.component.tsl

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-dashboard',
  templateUrl: './full-layout.component.html'
})
export class FullLayoutComponent {
  public navLinks;
  constructor(private router: Router) {
    this.navLinks = [];
    console.log('Into Full!!!!')
  }

  public activeTabLabel(code) {
    for (let count = 0; count < this.navLinks.length; count++) {
      if (this.navLinks[count].code === code) {
        this.navLinks[count].isActive = true;
      } else {
        this.navLinks[count].isActive = false;
      }
    }
  }

  public updateArrays(linkInfo) {
    let updateFlag = true;
    for (let count = 0; count < this.navLinks.length; count++) {
      if (linkInfo.code === this.navLinks[count].code) {
        this.navLinks[count].isActive = true;
        this.router.navigate([linkInfo.path]);
        updateFlag = false;
      } else {
        this.navLinks[count].isActive = false;
      }
    }
    if (updateFlag) {
      this.navLinks.push(linkInfo);
      this.navLinks[this.navLinks.length - 1].isActive = true;
      this.router.navigate([linkInfo.path]);
    }
  }

  closeTab(code) {
    for (let count = 0; count < this.navLinks.length; count++) {
      if (this.navLinks[count].code === code) {
        this.navLinks.splice(count, 1);
        this.navLinks[count - 1].isActive = true;
        this.router.navigate([this.navLinks[count - 1].path]);
        break;
      }
    }
  }
}

问题二:

追加与切换没问题,至于关闭功能,可能得自己加一个关闭的符号“✖”。待实现。

问题三:

Tab页的实现,如果基于mat-tab-group,这个feature是具备的,但是毕竟我们是基于nav mat-tab-nav-bar,所以官方Githubissue给出的结论是:还没实现。

问题四:

Tab页切换而不销毁组件,还在查。

上一篇 下一篇

猜你喜欢

热点阅读