Angular 动态创建多个页面

场景

最近胡思乱想,感觉网站通过路由切来切去不太好,特别是后台管理台,如果通过只打开一个浏览器页签,打开多个页面,这样就不用浏览器路由切来切去,以tab的形式打开多个页面,如果没有关闭,原来页面的数据就一直在,这样就不需要频繁打开页面,减少了服务器压力,二来好查看数据,于是说干就干。

动态加载组件

根据了解,angular可以通过ng-container动态加载不同的组件,其中ngComponentOutlet传入动态加载的组件名称就可以了

  1. <ng-container *ngComponentOutlet="PageComponent"></ng-container>

通过传入一个组件数组,动态添加需要的组件,然后页面遍历该数组

AdminComponent html 这里的tab使用的是 蚂蚁金服开源的ng-zorro-antd

  1. <nz-tabset [(nzSelectedIndex)]="selectedIndex" nzType="editable-card" [nzHideAdd]="true" (nzClose)="closeTab($event)">
  2. <nz-tab *ngFor="let tab of tabs; let i = index" [nzClosable]="i > 0" [nzTitle]="tab.name">
  3. <ng-container *ngComponentOutlet="tab.pageComponent"></ng-container>
  4. </nz-tab>
  5. </nz-tabset>

AdminComponent ts 其中我们的其他所有的组件都实现CommonComponent,一边传入的参数管理

  1. import { Component, OnInit } from '@angular/core';
  2. import { AuthService } from '../common-share/api/auth/auth.service';
  3. import { NzModalService } from 'ng-zorro-antd/modal';
  4. import { User } from '../common-share/model/user.model';
  5. import { CommonComponent } from './common/common.component';
  6. import { ComponentListService } from './common/componentlist.service';
  7. @Component({
  8. selector: 'app-admin',
  9. templateUrl: './admin.component.html',
  10. styleUrls: ['./admin.component.less']
  11. })
  12. export class AdminComponent implements OnInit {
  13. tabs : Array<{page:string,name:string, pageComponent:CommonComponent}> = [];
  14. //tab现在选择的是第几个
  15. selectedIndex = 0;
  16. constructor(private auth: AuthService,
  17. private modalService :NzModalService,
  18. private componentListService:ComponentListService,) {}
  19. ngOnInit() {
  20. //加载完先添加一个tab 首页
  21. this.newTab('adminIndex', '首页');
  22. }
  23. //关闭一个tab
  24. closeTab({ index }: { index: number }): void {
  25. this.tabs.splice(index, 1);
  26. }
  27. /**
  28. * @param _page 新增tab名称
  29. * @param _name
  30. */
  31. newTab(_page, _name): void {
  32. //判断存不存在该tab,存在直接切换过去退出
  33. let res :boolean = false;
  34. let checkIndex = 0;
  35. for (let index = 0; index < this.tabs.length; index++) {
  36. const element = this.tabs[index];
  37. if(element.page === _page){
  38. res = true;
  39. checkIndex = index;
  40. break;
  41. }
  42. }
  43. if(res){
  44. this.selectedIndex = checkIndex;
  45. return;
  46. }
  47. //把新加的tab放入tablist中
  48. this.tabs.push({page:_page, name:_name, pageComponent:null});
  49. //切换tab到新加的tab
  50. this.selectedIndex = this.tabs.length;
  51. //得到数组中tab位置
  52. const tabsIndex = this.selectedIndex - 1;
  53. //通过page名称取组件
  54. const oneTab = this.componentListService.getCommonItem(_page);
  55. //给组件赋值
  56. this.tabs[tabsIndex].pageComponent = oneTab.component;
  57. }
  58. }

CommonComponent

  1. import { Component, OnInit } from '@angular/core';
  2. @Component({
  3. selector: 'app-common',
  4. templateUrl: './common.component.html',
  5. styleUrls: ['./common.component.less']
  6. })
  7. export class CommonComponent {
  8. constructor() { }
  9. }

AccessAnalysisComponent 访问分析实现CommonComponent

  1. import { Component, OnInit } from '@angular/core';
  2. import { CommonComponent } from '../common/common.component';
  3. @Component({
  4. selector: 'app-access-analysis',
  5. templateUrl: './access-analysis.component.html',
  6. styleUrls: ['./access-analysis.component.less']
  7. })
  8. export class AccessAnalysisComponent implements CommonComponent {
  9. constructor() { }
  10. ngOnInit() {
  11. }
  12. }

ComponentListService 里面列举了所有可以加载的组件

  1. import { Injectable } from '@angular/core';
  2. import { CommonItem } from './common.item';
  3. import { ListComponent } from '../todolist/list/list.component';
  4. import { UsersComponent } from '../users/users.component';
  5. import { IndexComponent } from '../index/index.component';
  6. import { AccessAnalysisComponent } from '../access-analysis/access-analysis.component';
  7. import { PushAnalysisComponent } from '../push-analysis/push-analysis.component';
  8. import { AddPushMailComponent } from '../push-mail/add-push-mail/add-push-mail.component';
  9. import { PushMailHistoryComponent } from '../push-mail/push-mail-history/push-mail-history.component';
  10. @Injectable()
  11. export class ComponentListService {
  12. private componentList: Array<{key:string, item:CommonItem}> = [
  13. {
  14. key: "adminIndex", item: new CommonItem(IndexComponent, {})
  15. },{
  16. key: "accessAnalysis", item : new CommonItem(AccessAnalysisComponent, {})
  17. },{
  18. key: "pushAnalysis", item : new CommonItem(PushAnalysisComponent, {})
  19. },{
  20. key: "addPushMail", item : new CommonItem(AddPushMailComponent, {})
  21. },{
  22. key: "pushMailHistory", item : new CommonItem(PushMailHistoryComponent, {})
  23. },{
  24. key: "userList", item : new CommonItem(UsersComponent, {})
  25. },{
  26. key: "todoList", item : new CommonItem(ListComponent, {})
  27. },
  28. ];
  29. getComponentList() {
  30. return this.componentList;
  31. }
  32. getCommonItem(_key): CommonItem{
  33. let res = null;
  34. this.componentList.forEach(element => {
  35. if(element.key == _key){
  36. res = element.item;
  37. }
  38. });
  39. return res;
  40. }
  41. }

CommonItem 用来定义组件,封装数据,如果需要的话

  1. import { Type } from '@angular/core';
  2. export class CommonItem {
  3. constructor(public component: Type<any>, public data: any) {}
  4. }

效果图

其中的访问分析和推送分析,原来是选哟通过路由打开不同的页面,现在可以在一个页面,切换tab就可以看不同的数据。同时已经加载的也不会重复加载