管理系统 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代码如下:

      

 import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';

 export class SimpleReuseStrategy implements RouteReuseStrategy {

     public static handlers: { [key: string]: DetachedRouteHandle } = {}

     /** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
} /** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
SimpleReuseStrategy.handlers[route.routeConfig.path] = handle
} /** 若 path 在缓存中有的都认为允许还原路由 */
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!route.routeConfig && !!SimpleReuseStrategy.handlers[route.routeConfig.path]
} /** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null
} return SimpleReuseStrategy.handlers[route.routeConfig.path]
} /** 进入路由触发,判断是否同一路由 */
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig
}
}

   

 

  二、策略注册到模块当中:

    

 import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule as SystemCommonModule } from '@angular/common';
import { AppComponent } from './app.component';
import { AppRoutingModule,ComponentList } from './app.routing'
import { SimpleReuseStrategy } from './SimpleReuseStrategy';
import { RouteReuseStrategy } from '@angular/router'; @NgModule({
declarations: [
AppComponent,
ComponentList
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
SystemCommonModule
],
providers: [
{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy }
],
bootstrap: [AppComponent]
})
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代码如下:

 import { Component } from '@angular/core';
import { SimpleReuseStrategy } from './SimpleReuseStrategy';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Title } from '@angular/platform-browser';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap'; @Component({
selector: 'app-root',
styleUrls:['app.css'],
templateUrl: 'app.html',
providers: [SimpleReuseStrategy]
}) export class AppComponent { //路由列表
menuList: Array<{ title: string, module: string, power: string,isSelect:boolean }>=[]; constructor(private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title) { //路由事件
this.router.events.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter(route => route.outlet === 'primary')
.mergeMap(route => route.data)
.subscribe((event) => {
//路由data的标题
let title = event['title'];
this.menuList.forEach(p => p.isSelect=false);
var menu = { title: title, module: event["module"], power: event["power"], isSelect:true};
this.titleService.setTitle(title);
let exitMenu=this.menuList.find(info=>info.title==title);
if(exitMenu){//如果存在不添加,当前表示选中
this.menuList.forEach(p => p.isSelect=p.title==title);
return ;
}
this.menuList.push(menu);
});
} //关闭选项标签
closeUrl(module:string,isSelect:boolean){
//当前关闭的是第几个路由
let index=this.menuList.findIndex(p=>p.module==module);
//如果只有一个不可以关闭
if(this.menuList.length==1) return ; this.menuList=this.menuList.filter(p=>p.module!=module);
//删除复用
delete SimpleReuseStrategy.handlers[module];
if(!isSelect) return;
//显示上一个选中
let menu=this.menuList[index-1];
if(!menu) {//如果上一个没有下一个选中
menu=this.menuList[index+1];
}
// console.log(menu);
// console.log(this.menuList);
this.menuList.forEach(p => p.isSelect=p.module==menu.module );
//显示当前路由信息
this.router.navigate(['/'+menu.module]);
}
}

  app.html 的代码如下:

 <div class="row">
<div class="col-md-4">
<ul>
<li><a routerLinkActive="active" routerLink="/home">首页</a></li>
<li><a routerLinkActive="active" routerLink="/about">关于我们</a></li>
<li><a routerLinkActive="active" routerLink="/news">新闻中心</a></li>
<li><a routerLinkActive="active" routerLink="/contact">联系我们</a></li>
</ul>
</div>
<div class="col-md-8">
<div class="crumbs clearfix">
<ul>
<ng-container *ngFor="let menu of menuList">
<ng-container *ngIf="menu.isSelect">
<li class="isSelect">
<a routerLink="/{{ menu.module }}">{{ menu.title }}</a>
<span (click)="closeUrl(menu.module,menu.isSelect)">X</span>
</li>
</ng-container>
<ng-container *ngIf="!menu.isSelect">
<li>
<a routerLink="/{{ menu.module }}">{{ menu.title }}</a>
<span (click)="closeUrl(menu.module,menu.isSelect)">X</span>
</li>
</ng-container>
</ng-container>
</ul>
</div>
<router-outlet></router-outlet>
</div>
</div>

整体效果如下:

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

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

angular 4 实现的tab栏切换的更多相关文章

  1. jQuery带有定时器的tab栏切换

    现在网上很多类似选项卡的切换,我们成为tab栏切换,比如下图: 新浪的tab栏切换 淘宝的tab栏切换 其中,新浪的tab栏鼠标放上去,可以快速的来回切换,但是如果采取ajax异步传输,不停去加载服务 ...

  2. dataTable tab栏切换时错位解决办法

    做后台管理类网站肯定要写列表,首选dataTable,功能强大 最近在做一个tab栏切换时发现了一个很诡异的事情:表头错位了! 主要时因为当table被隐藏后,table的header宽度会计算错乱, ...

  3. tab栏切换

    最简单的tab栏切换 html部分 <ul class="tab"> <li class="item">待支付(1)</li> ...

  4. tab栏切换制作

    tab栏切换制作 先上图 要求1:默认状态,第一个选项卡被选中,展示第一个选项卡的内容 策略:第一个选项卡默认有被选中的样式,第一个选项卡对应的display: block,其他的dispaly设为n ...

  5. ES6面向对象实现tab栏切换效果

    面向对象实现tab栏切换效果

  6. JS实现 Tab栏切换案例

    要求:当鼠标点击上面相应的选项卡(tab),下面页面的内容也随之而改变. 结构分析: 全部的内容都放到一个大的盒子里面,盒子里面又可以分为上面和下面两个盒子. 上面的盒子放了 5个li,装着5个小的选 ...

  7. angular实现的tab栏切换

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. tab栏切换的特殊效果

    在实际的开发过程中,我们可能会遇到这种需求,如下图 左边是三个tab栏,右边是显示内容的div,当鼠标滑到坐标的tab上时,给它一个高亮显示,让它对应的内容在右边的div中显示出来,当鼠标移出的时候把 ...

  9. JavaScript实现Tab栏切换

    本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 京东网页上,可以看到下面这种tab栏的切换: 我们把模型抽象出来,实现一 ...

随机推荐

  1. 201521123014 《Java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 Q1. 代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通 ...

  2. 201521123017 《Java程序设计》第3周学习总结

    1. 本周学习总结 2. 书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...

  3. 201521123022 《Java程序设计》第三周学习总结

    1.本周学习总结 2.书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; pu ...

  4. 201521123007《Java程序设计》第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...

  5. 快递鸟顺丰物流api接口对接多种方法整理

    目前很多自营电商平台.ERP系统.仓储系统.快递柜企业,对物流模块数据需求还是比较旺盛的.之前有介绍过简单的接口对接方法,这次给大家整理介绍两种快递数据的获取方法. 接口秘钥可以向顺丰公司申请,或者一 ...

  6. elasticsearch 中文分词、插件的安装和使用(一)

    1. 安装elasticsearch.kibana.x-pack #安装elasticsearch wget https://artifacts.elastic.co/downloads/elasti ...

  7. 如何快速成长?我的java之路!

    由于一些外部的原因,我不得不从自己熟悉的php领域,转战到java战场.我个人觉得还是有些心得吧,不管怎么样,或多或少可能都会有那么些经历的人,和你一起走在这世上!尽管你不知道TA是谁. 其实,转换一 ...

  8. Linux 内核模块程序结构

    1.内核加载函数 即我们常说的内核入口函数,当内核被加载的时候调用,在内核入口函数中多进行设备的注册和初始化,其中最常用的莫过于module_init().insmod xxx.ko的时候调用. 通常 ...

  9. webpack2系列step1

    第一篇:HTML 本文将一步一步的介绍webpack2的配置,从最基础的一直到与node结合. 操作都一样: midir step1 && cd step1 npm init -y n ...

  10. 彻底弄懂AngularJS中的transclusion

    点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...