前段時間在后台管理端要實現的一個需求是做個類似瀏覽器中的標簽欄。方便用戶在不同報表中查看和比對。
查了一些方法,可以通過angular的動態組件方式實現和路由復用的方式實現。
動態組件大體上就是把每個打開的頁放入到componentFactory中,然后判斷當前應該顯示哪個頁就好了。
簡化的例子,請點擊這里。
路由復用
顯然這種方式是更合理的,首先實現RouteReuseStrategy中的方法,判斷各路由是否使用復用、存儲和刪除。
app.module.ts
providers: [
{provide: RouteReuseStrategy, useClass: SimpleReuseStrategy },
...
simpleReuseStrategy.ts
export class SimpleReuseStrategy implements RouteReuseStrategy { public static handlers: { [key: string]: DetachedRouteHandle } = {}; private static waitDelete: string; public static deleteRouteSnapshot(name: string): void { if (SimpleReuseStrategy.handlers[name]) { delete SimpleReuseStrategy.handlers[name]; } else { SimpleReuseStrategy.waitDelete = name; } } public static getRouteUrl(route: ActivatedRouteSnapshot) { return route['_routerState'].url.replace(/\/|\?|&|=/g, '_'); } /** 表示對所有路由允許復用 如果你有路由不想利用可以在這加一些業務邏輯判斷 */ public shouldDetach(route: ActivatedRouteSnapshot): boolean { if (!route.routeConfig || route.routeConfig.loadChildren ||!route.routeConfig.data
|| (route.routeConfig.data&&!route.routeConfig.data.useCache)) { return false; } return true; } /** 當路由離開時會觸發。按url作為key存儲路由快照&組件當前實例對象 */ public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { const routeKey = SimpleReuseStrategy.getRouteUrl(route); if (SimpleReuseStrategy.waitDelete && SimpleReuseStrategy.waitDelete === routeKey) { // 如果待刪除是當前路由則不存儲快照 SimpleReuseStrategy.waitDelete = null; return; } SimpleReuseStrategy.handlers[routeKey] = handle; } /** 若 url 在緩存中有的都認為允許還原路由 */ public shouldAttach(route: ActivatedRouteSnapshot): boolean { let isShow = route.routeConfig.data&&route.routeConfig.data.useCache; return !!SimpleReuseStrategy.handlers[SimpleReuseStrategy.getRouteUrl(route)]&&isShow; } /** 從緩存中獲取快照,若無則返回nul */ public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { if (!route.routeConfig) { return null; } // if (route.routeConfig.loadChildren) return null; const routeKey = SimpleReuseStrategy.getRouteUrl(route); return SimpleReuseStrategy.handlers[routeKey]; } /** 進入路由觸發,判斷是否同一路由 */ public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { const a = future.routeConfig === curr.routeConfig && JSON.stringify(future.params) === JSON.stringify(curr.params); return a; } }
這里是我處理路由事件和標簽欄的service,需要注意的要訂閱的是 ActivationEnd 這路由事件。它會帶有當前的路由信息。
export class DealWithTabService { tabList: Array<Tab> = []; tabsMaxLength = 15; constructor(public router: Router) { abp.event.on('Tab.sendTabList', () => { abp.event.trigger('getTabList', (this.tabList)); }); this.router.events.filter(event => event instanceof ActivationEnd) .subscribe((event) => { const snapshot = (event as ActivationEnd).snapshot; if (snapshot['_routerState'].url && snapshot.routeConfig.data && snapshot.routeConfig.data.useCache) { let key = snapshot['_routerState'].url.replace(/\/|\?|&|=/g, '_'); const exitMenu = this.tabList.find(info => info.url === key); if (exitMenu) { this.tabList.forEach(p => p.isSelect = p.url === key); return; } let title = snapshot.routeConfig.data.title; this.getTab(snapshot.routeConfig, snapshot.queryParams, snapshot['_routerState'].url, title); } }); } public getTab(routeConfig, queryParams, url, title) { let isShow = routeConfig.data && routeConfig.data.useCache; if (!isShow) { return; } let key = url.replace(/\/|\?|&|=/g, '_'); const exitMenu = this.tabList.find(info => { info.isSelect = false; return info.url === key; }); if (exitMenu) { // 如果存在不添加,當前表示選中 this.tabList.forEach(p => p.isSelect = p.url === key); return; } let title1 = (queryParams && queryParams.title) ? '[' + queryParams.title + ']' : ''; const tab = { title: title + title1, module: routeConfig.data.module, queryParams: queryParams, // 因為我使用了queryParams傳參,不建議,我的感覺,處理起來麻煩很多 url: key, isSelect: true }; this.tabList.push(tab); this.sliceTabs(); } public deleteTabCache(tab: Tab) { // 當前關閉的是第幾個路由 const index = this.tabList.findIndex(p => p.url === tab.url); // 如果只有一個不可以關閉 if (this.tabList.length === 1) { return; } if (tab.isSelect) { // 顯示上一個選中 let menu = this.tabList[index - 1]; if (!menu) { // 如果上一個沒有下一個選中 menu = this.tabList[index + 1]; } // console.log(menu); // console.log(this.menuList); this.tabList.forEach(p => p.isSelect = p.url === menu.url); // 顯示當前路由信息 this.routerNavigate(menu); } this.tabList = this.tabList.filter(p => p.url != tab.url); // 刪除復用 SimpleReuseStrategy.deleteRouteSnapshot(tab.url); this.sliceTabs(); }
... }