原始需求:
一个正常的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
,所以官方Github
的issue
给出的结论是:还没实现。
问题四:
Tab页切换而不销毁组件,还在查。
网友评论