zoukankan      html  css  js  c++  java
  • 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>

     整体效果如下:

    最终点击菜单显示相应的标签选中,可以切换编辑内容,关闭标签时,重新点击菜单可以重新加载内容。

    源代码:好吧,我不知道怎样上传源代码:)!

  • 相关阅读:
    C# WinForm开发系列 OpenSource Controls
    Jenkins_FileCenter_Deploy
    DatabaseOperation_DBM Kill inactive connection
    如何在linux下检测内存泄漏
    基本数据类型
    Linux Kernel Makefiles
    让GCC编译关键字“__attribute__”给你带来方便
    内核空间和用户空间
    程序人生--一个程序员对学弟学妹建议
    arm linux
  • 原文地址:https://www.cnblogs.com/lslgg/p/7700888.html
Copyright © 2011-2022 走看看