1. 程式人生 > >使用angular路由複用策略實現標籤欄效果

使用angular路由複用策略實現標籤欄效果

前段時間在後臺管理端要實現的一個需求是做個類似瀏覽器中的標籤欄。方便使用者在不同報表中檢視和比對。

查了一些方法,可以通過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();
    }

   ... }

 

簡化的例子,請點選這裡