tabs.component.ts 4.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
import {
  AfterContentChecked,
  AfterContentInit, AfterViewInit,
  Component,
  ComponentFactoryResolver,
  Injector, OnDestroy,
  OnInit,
  QueryList, ViewChild,
  ViewChildren,
  ViewContainerRef
} from '@angular/core';
import {ActivatedRoute, ActivationEnd, NavigationEnd, Router, RouterLink, RouterLinkWithHref} from '@angular/router';
import {Observable, Subscription} from "rxjs";

@Component({
  selector: 'app-tabs',
  templateUrl: './tabs.component.html',
  styleUrls: ['./tabs.component.scss']
})
export class TabsComponent implements OnInit, OnDestroy, AfterViewInit {

  @ViewChildren(RouterLinkWithHref) links: QueryList<RouterLinkWithHref>;
  @ViewChildren('container', {read: ViewContainerRef}) containers: QueryList<ViewContainerRef>;

  current = 0;

  tabs: Array<any> = [];

  event: any;
  sub: Subscription;

  constructor(private router: Router, private resolver: ComponentFactoryResolver, private location: ViewContainerRef) {
    this.sub = router.events.subscribe((e: any) => {
      // console.log('router event', e);
      if (e instanceof ActivationEnd && !e.snapshot.firstChild) {
        this.event = e;
        return;
      }

      if (e instanceof NavigationEnd) {
        //   //TODO 第一次,container还未准备好
        //   //TODO 添加路由参数
        //   //TODO call ref.destroy() in ngOnDestroy
        this.checkRouter(e.url);
      }
    });
  }

  checkRouter(url): void {
    if (!this.links) {
      return;
    }
J
Jason 已提交
53

J
优化  
Jason 已提交
54
    // TODO 要判断是 /admin/ 起始
J
Jason 已提交
55 56
    const path = url.replace(/^\/admin\//, '');

J
优化  
Jason 已提交
57 58 59 60 61 62
    // 快速查找
    let index = this.tabs.findIndex(tab => tab.route === path);
    // 通过Angular路由查找
    if (index < 0 && this.links) {
      index = this.links.toArray().findIndex(link => this.router.isActive(link.urlTree, true));
    }
63 64
    if (index > -1) {
      this.current = index;
J
优化  
Jason 已提交
65
      return;
66
    }
J
优化  
Jason 已提交
67 68 69 70 71 72 73 74 75 76

    // 创建新标签
    this.current = this.tabs.length;
    this.tabs.push({
      name: path,
      route: path
    });
    setTimeout(() => {
      this.onTabsChange(this.tabs.length - 1);
    }, 100);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  }

  ngAfterViewInit(): void {
    this.checkRouter(this.router.url);
  }

  ngOnInit(): void {
  }

  ngOnDestroy(): void {
    this.sub.unsubscribe();
    this.tabs.forEach(tab => {
      if (tab.component) {
        tab.component.destroy();
      }
    });
  }

  onTabsChange(index): void {
    this.current = index;
    this.loadTab(index);
  }

  onTabClose(index): void {
101 102 103
    if (this.tabs.length === 1) {
      //TODO 打开默认页
      return;
104
    }
105 106

    const tab = this.tabs.splice(index, 1)[0];
107 108 109
    if (tab.component) {
      tab.component.destroy();
    }
110 111 112 113 114 115 116 117 118 119
    if (this.current > index) {
      this.current--;
    } else if (this.current === index) {
      if (this.current >= this.tabs.length) {
        this.current = this.tabs.length - 1;
      }
      // 用修改路由的方式触发
      this.router.navigate(['/admin/' + this.tabs[this.current].route]);
      return;
    }
120 121 122 123
  }

  loadTab(index): void {
    if (this.tabs[index].component) {
J
Jason 已提交
124
      //TODO setTitle
125 126 127 128 129 130 131 132
      return;
    }

    // this.router.routerState.snapshot.root.firstChild.firstChild.firstChild...
    let route: any = this.router.routerState.snapshot.root;
    while (route.firstChild) {
      route = route.firstChild;
    }
J
Jason 已提交
133 134 135 136 137 138 139 140
    // TODO 如果route.component为空,则找不到内容
    if (route.component) {
      const factory = this.resolver.resolveComponentFactory(route.component);
      const injector = new TabsInjector(this.event, this.location.injector);

      const container = this.containers.toArray()[index];
      container.clear();
      this.tabs[index].component = container.createComponent(factory, this.location.length, injector);
J
Jason 已提交
141
      //TODO setTitle
J
Jason 已提交
142
    }
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  }

}

class TabsInjector implements Injector {
  constructor(private route: ActivatedRoute, private parent: Injector) {
  }

  get(token: any, notFoundValue?: any): any {
    if (token === ActivatedRoute) {
      return this.route;
    }
    return this.parent.get(token, notFoundValue);
  }
}