美文网首页
基于Material2的Tab实现

基于Material2的Tab实现

作者: 环零弦 | 来源:发表于2017-11-28 15:48 被阅读0次

    原始需求:

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

    具体功能描述:

    • 根据左侧Navigator,在页面Middle部分动态加载Tab页,Content部分是由路由决定的组件。
    • Tab页可以追加、切换和关闭。
    • Tab页在打开过多的情况下可以左右箭头移动。
    • Tab页的切换(包括关闭等一系列操作)不会引起组件的销毁。

    具体实现:

    问题一:

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

    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页切换而不销毁组件,还在查。

    相关文章

      网友评论

          本文标题:基于Material2的Tab实现

          本文链接:https://www.haomeiwen.com/subject/mlcebxtx.html