某商城前端架构总结与反思(angular路由复用)

  • 邢毅彪
  • 28 Minutes
  • 2018年6月28日

前言

在后台管理项目中,为实现选项卡功能,除了iframe,angular提供的路由复用是个很好的实现

实现

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
53
54
55
56
57
58
59
60
// share/simple-reuse-strategy.ts
import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';

export class SimpleReuseStrategy implements RouteReuseStrategy {

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

private static waitDelete:string

/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
const { path } = route.routeConfig
// console.log(SimpleReuseStrategy.handlers)
if (path === '') { // 主页面不缓存
return false
}
return true;
}

/** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if(SimpleReuseStrategy.waitDelete && SimpleReuseStrategy.waitDelete == this.getRouteUrl(route)){
//如果待删除是当前路由则不存储快照
SimpleReuseStrategy.waitDelete = null
return;
}
SimpleReuseStrategy.handlers[this.getRouteUrl(route)] = handle
}

/** 若 path 在缓存中有的都认为允许还原路由 */
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!SimpleReuseStrategy.handlers[this.getRouteUrl(route)]
}

/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null
}

return SimpleReuseStrategy.handlers[this.getRouteUrl(route)]
}

/** 进入路由触发,判断是否同一路由 */
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params);
}

private getRouteUrl(route: ActivatedRouteSnapshot){
return route['_routerState'].url.replace(/\//g,'_')
}
public static deleteRouteSnapshot(name: string): void{
if (SimpleReuseStrategy.handlers[name]) {
delete SimpleReuseStrategy.handlers[name];
} else {
SimpleReuseStrategy.waitDelete = name;
}
}
}
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// root.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthServiceService, Menu, MainItem, UserInfo } from '../../serves/auth-service/auth-service.service';
import { NzMessageService } from 'ng-zorro-antd';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { SimpleReuseStrategy } from '../../share/simple-reuse-strategy';
import { Title } from '@angular/platform-browser';
import { filter, map, mergeMap } from "rxjs/operators";

@Component({
selector: 'app-root',
templateUrl: './root.component.html',
styleUrls: ['./root.component.scss'],
providers: [SimpleReuseStrategy]
})
export class RootComponent implements OnInit {

constructor(private auth: AuthServiceService,
private msg: NzMessageService,
private router: Router,
private activedRoute: ActivatedRoute,
private titleService: Title
) {
// 路由事件
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activedRoute),
map((route) => {
while (route.firstChild) {
route = route.firstChild
}
return route
}),
filter((route) => {
return route.outlet === 'primary'
}),
mergeMap((route) => {return route.data})
)
.subscribe((event) => {
// 路由标题
let title = event['title']
this.mainItems.forEach((item) => {
item.isSelect = false
})

// 如果没有title,则视为无用路由
if (!title) {
return
}

const menu: MainItem = {
title: title,
module: event['module'],
power: event['power'],
isSelect: true
}

this.titleService.setTitle(`企业管理平台--${title}`)

const exitMenu = this.mainItems.find((item) => { return item.title === title })
if (exitMenu) { // 如果存在
this.mainItems.forEach((item) => { item.isSelect = item.title === title })
return
}
this.mainItems.push(menu)
})
}

// 菜单列表
public menus: Menu[] = []

// 用户信息
public userInfo: UserInfo

// 路由列表
public mainItems: MainItem[] = []

// 菜单是否折叠
public isCollapsed: boolean = false

private routerEvent() {

}

ngOnInit() {
this.auth.getAuth()
.subscribe(
(res) => {
const { status, msg, data } = res
if (status === 200) {
this.menus = data.menus
this.userInfo = data.userInfo
this.auth.menus.emit(data.menus)
} else {
this.msg.error(msg)
}
},
() => {
this.msg.error('网络错误,请稍后重试!')
}
)

this.routerEvent()
}

// 关闭标签页
public closeUrl(module: string, isSelect: boolean): void {
// 当前关闭的是第几个路由
let index = this.mainItems.findIndex((item) => { return item.module === module })
// 如果只有一个不可关闭
if (this.mainItems.length === 1) {
return
}

this.mainItems = this.mainItems.filter((item) => item.module !== module)
// 删除复用
delete SimpleReuseStrategy.handlers[module]
if (!isSelect) {
return
}
// 显示上一个
if (index === 0) {
this.mainItems[index].isSelect = true
} else {
this.mainItems[index - 1].isSelect = true
}

const menu = this.mainItems.filter((item) => item.isSelect)[0]
this.router.navigate(['/' + menu.module])
}

// 监听左侧菜单
public changeCollapsed(isCollapsed: boolean) {
this.isCollapsed = isCollapsed
}

}
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
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { FileUploadModule } from 'ng2-file-upload'

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd'
import { HttpClientModule } from '@angular/common/http';
import { httpInterceptorProviders } from './http-interceptors';
import { AuthServiceService } from './serves/auth-service/auth-service.service';
import { SimpleReuseStrategy } from './share/simple-reuse-strategy';
import { RouteReuseStrategy } from '@angular/router';


@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
HttpClientModule,
FileUploadModule,
NgZorroAntdModule.forRoot(),
AppRoutingModule,
],
providers: [
AuthServiceService,
httpInterceptorProviders,
{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy },
{ provide: NZ_I18N, useValue: zh_CN } // ng-zorro国际化服务,必须注入
],
bootstrap: [AppComponent]
})
export class AppModule { }
访问量