angular 4 實現的tab欄切換


管理系統 tab 切換頁,是一種常見的需求,大概如下:

點擊左邊菜單,右邊顯示相應的選項卡,然后不同的選項卡面可以同時編輯,切換時信息不掉失!

用php或.net,java的開發技術,大概是切換顯示,然后加一個ifram來做到,或者通過ajax加載信息顯示相應的層.

但是如果用angular 要如何實現呢?第一個想法,是否可以用同樣的ifarm來實現呢?

第二個想到的是路由插座大概是這樣的

<router-outlet name="main-content" (activate)="activate($event)" (deactivate)='onDeactivate($event)' ></router-outlet> 

但都沒能實現,於是在想一個簡單的tab頁面就這么難嗎?

或者真的沒有什么簡單的方法了嗎?

很長一段時間,沒有去管這個了

因為我知道自己對angular的理解和學習還不夠,於是就放下了很長一段時間,直到在知乎看到一篇文章

Angular路由復用策略

於是有了一種思路,花了半天的時間終於實現了anguar 4  tab 切換頁大概思路實現如下:

  一、實現 RouteReuseStrategy 接口自定義一個路由利用策略

    SimpleReuseStrategy.ts代碼如下:

      

 1 import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
 2 
 3 export class SimpleReuseStrategy implements RouteReuseStrategy {
 4 
 5     public static handlers: { [key: string]: DetachedRouteHandle } = {}
 6 
 7     /** 表示對所有路由允許復用 如果你有路由不想利用可以在這加一些業務邏輯判斷 */
 8     public shouldDetach(route: ActivatedRouteSnapshot): boolean {
 9         return true;
10     }
11 
12     /** 當路由離開時會觸發。按path作為key存儲路由快照&組件當前實例對象 */
13     public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
14         SimpleReuseStrategy.handlers[route.routeConfig.path] = handle
15     }
16 
17     /** 若 path 在緩存中有的都認為允許還原路由 */
18     public shouldAttach(route: ActivatedRouteSnapshot): boolean {
19         return !!route.routeConfig && !!SimpleReuseStrategy.handlers[route.routeConfig.path]
20     }
21 
22     /** 從緩存中獲取快照,若無則返回nul */
23     public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
24         if (!route.routeConfig) {
25             return null
26         }
27         
28         return SimpleReuseStrategy.handlers[route.routeConfig.path]
29     }
30 
31     /** 進入路由觸發,判斷是否同一路由 */
32     public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
33         return future.routeConfig === curr.routeConfig
34     }
35 }

 

   

 

  二、策略注冊到模塊當中:

    

 1 import { BrowserModule } from '@angular/platform-browser';
 2 import { NgModule } from '@angular/core';
 3 import { FormsModule } from '@angular/forms';
 4 import { CommonModule as SystemCommonModule } from '@angular/common';
 5 import { AppComponent } from './app.component';
 6 import { AppRoutingModule,ComponentList } from './app.routing'
 7 import { SimpleReuseStrategy } from './SimpleReuseStrategy';
 8 import { RouteReuseStrategy } from '@angular/router';
 9 
10 @NgModule({
11   declarations: [
12     AppComponent,
13     ComponentList
14   ],
15   imports: [
16     BrowserModule,
17     AppRoutingModule,
18     FormsModule,
19     SystemCommonModule
20   ],
21   providers: [
22     { provide: RouteReuseStrategy, useClass: SimpleReuseStrategy }
23   ],
24   bootstrap: [AppComponent]
25 })
26 export class AppModule { }

 

   上面兩步基本上實現了復用策略但要實現第一張效果圖,還是要做一些其它工作

  三、定義路由添加一些data數據路由代碼如下:

    

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './home/about.component'
import { HomeComponent } from './home/home.component'
import { NewsComponent } from './home/news.component'
import { ContactComponent } from './home/contact.component'



export const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full', },
  { path: 'home', component: HomeComponent,data: { title: '首頁', module: 'home', power: "SHOW" } },
  { path: 'news',component: NewsComponent ,data: { title: '新聞管理', module: 'news', power: "SHOW" }},
  { path: 'contact',component: ContactComponent ,data: { title: '聯系我們', module: 'contact', power: "SHOW" }},
  { path: 'about', component: AboutComponent,data: { title: '關於我們', module: 'about', power: "SHOW" } },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class AppRoutingModule { }

export const ComponentList=[
    HomeComponent,
    NewsComponent,
    AboutComponent,
    ContactComponent
]

 

  四、在<router-outlet></router-outlet> component 實現路由事件  events,app.component代碼如下:

 1 import { Component } from '@angular/core';
 2 import { SimpleReuseStrategy } from './SimpleReuseStrategy';
 3 import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
 4 import { Title } from '@angular/platform-browser';
 5 import 'rxjs/add/operator/filter';
 6 import 'rxjs/add/operator/map';
 7 import 'rxjs/add/operator/mergeMap';
 8 
 9 @Component({
10   selector: 'app-root',
11   styleUrls:['app.css'],
12   templateUrl: 'app.html',
13   providers: [SimpleReuseStrategy]
14 })
15 
16 export class AppComponent {
17   
18   //路由列表
19   menuList: Array<{ title: string, module: string, power: string,isSelect:boolean }>=[];
20 
21   constructor(private router: Router,
22     private activatedRoute: ActivatedRoute,
23     private titleService: Title) {
24   
25     //路由事件
26     this.router.events.filter(event => event instanceof NavigationEnd)
27       .map(() => this.activatedRoute)
28       .map(route => {
29         while (route.firstChild) route = route.firstChild;
30         return route;
31       })
32       .filter(route => route.outlet === 'primary')
33       .mergeMap(route => route.data)
34       .subscribe((event) => {
35         //路由data的標題
36         let title = event['title'];
37         this.menuList.forEach(p => p.isSelect=false);
38         var menu = { title: title, module: event["module"], power: event["power"], isSelect:true};
39         this.titleService.setTitle(title);
40         let exitMenu=this.menuList.find(info=>info.title==title);
41         if(exitMenu){//如果存在不添加,當前表示選中
42           this.menuList.forEach(p => p.isSelect=p.title==title);
43           return ;
44         } 
45         this.menuList.push(menu);
46       });
47   }
48 
49   //關閉選項標簽
50   closeUrl(module:string,isSelect:boolean){
51     //當前關閉的是第幾個路由
52     let index=this.menuList.findIndex(p=>p.module==module);
53     //如果只有一個不可以關閉
54     if(this.menuList.length==1) return ;
55 
56     this.menuList=this.menuList.filter(p=>p.module!=module);
57     //刪除復用
58     delete SimpleReuseStrategy.handlers[module];
59     if(!isSelect) return;
60     //顯示上一個選中
61     let menu=this.menuList[index-1];
62     if(!menu) {//如果上一個沒有下一個選中
63        menu=this.menuList[index+1];
64     }
65     // console.log(menu);
66     // console.log(this.menuList);
67     this.menuList.forEach(p => p.isSelect=p.module==menu.module );
68     //顯示當前路由信息
69     this.router.navigate(['/'+menu.module]);
70   }
71 }

   app.html 的代碼如下:

 1 <div class="row">
 2   <div class="col-md-4">
 3     <ul>
 4       <li><a routerLinkActive="active" routerLink="/home">首頁</a></li>
 5       <li><a routerLinkActive="active" routerLink="/about">關於我們</a></li>
 6       <li><a routerLinkActive="active" routerLink="/news">新聞中心</a></li>
 7       <li><a routerLinkActive="active" routerLink="/contact">聯系我們</a></li>
 8     </ul>
 9   </div>
10   <div class="col-md-8">
11     <div class="crumbs clearfix">
12       <ul>
13           <ng-container  *ngFor="let menu of menuList">
14               <ng-container *ngIf="menu.isSelect">
15                   <li class="isSelect">
16                       <a routerLink="/{{ menu.module }}">{{ menu.title }}</a> 
17                       <span (click)="closeUrl(menu.module,menu.isSelect)">X</span> 
18                   </li>
19               </ng-container>
20               <ng-container *ngIf="!menu.isSelect">
21                   <li>
22                       <a routerLink="/{{ menu.module }}">{{ menu.title }}</a> 
23                       <span  (click)="closeUrl(menu.module,menu.isSelect)">X</span> 
24                   </li>
25               </ng-container>
26           </ng-container>
27       </ul>
28     </div>
29     <router-outlet></router-outlet>
30   </div>
31 </div>

 整體效果如下:

最終點擊菜單顯示相應的標簽選中,可以切換編輯內容,關閉標簽時,重新點擊菜單可以重新加載內容。

源代碼:好吧,我不知道怎樣上傳源代碼:)!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM