Dojo 路由

路由

dojo/framework/src/routing/README.md

commit b682b06ace25eea86d190e56dd81042565b35ed1git

Dojo 應用程序的路由github

Features

部件(Widget)是 Dojo 應用程序的基本概念,所以 Dojo 路由提供了一組與應用程序中的部件直接集成的組件。這些組件能將部件註冊到路由上,且不須要掌握路由相關的任何知識。Dojo 應用程序中的路由包括如下內容:fetch

  • Outlet 部件封裝器指定 route 的 outlet key 和表現視圖之間的映射關係
  • Route 配置,用於在路徑和 outlet key 之間創建映射關係
  • Router 基於當前路徑解析 Route
  • History 提供器負責向 Router 通知路徑的更改
  • RegistryRouter 注入到部件系統中

Route 配置

RouteConfig 用於註冊應用程序的路由,它定義了路由的 path、關聯的 outlet 以及嵌套的子 RouteConfig。一個完整的路由就是由遞歸嵌套的 Route 構成的。code

路由配置示例:

import { RouteConfig } from '@dojo/framework/routing/interfaces';

const config: RouteConfig[] = [
    {
        path: 'foo',
        outlet: 'root',
        children: [
            {
                path: 'bar',
                outlet: 'bar'
            },
            {
                path: 'baz',
                outlet: 'baz',
                children: [
                    {
                        path: 'qux',
                        outlet: 'qux'
                    }
                ]
            }
        ]
    }
];

此配置將註冊如下路由和 outlet:

Route Outlet
/foo root
/foo/bar bar
/foo/baz baz
/foo/baz/qux qux

路徑參數

RouteConfig 的 path 屬性中,在 path 的值中使用大括號可定義路徑參數。 Parameters will match any segment and the value of that segment is made available to matching outlets via the mapParams Outlet options. The parameters provided to child outlets will include any parameters from matching parent routes.

const config = [
    {
        path: 'foo/{foo}',
        outlet: 'foo'
    }
];

具備路徑參數的路由,可爲每一個路由指定默認的參數。當用沒有指定參數的 outlet 生成一個連接,或者當前路由中不存在參數時,可以使用這些默認參數值。

const config = [
    {
        path: 'foo/{foo}',
        outlet: 'foo',
        defaultParams: {
            foo: 'bar'
        }
    }
];

可以使用可選的配屬屬性 defaultRoute 來設置默認路由,若是當前路由沒有匹配到已註冊的路由,就使用此路由。

const config = [
    {
        path: 'foo/{foo}',
        outlet: 'foo',
        defaultRoute: true
    }
];

Router

Router 用於註冊 route 配置,將 route 配置信息傳入 Router 的構造函數便可:

const router = new Router(config);

會自動爲 router 註冊一個 HashHistory 歷史管理器(history manager)。可在第二個參數中傳入其餘歷史管理器。

import { MemoryHistory } from '@dojo/framework/routing/MemoryHistory';

const router = new Router(config, { HistoryManager: MemoryHistory });

使用應用程序路由配置建立路由後,須要讓應用程序中的全部組件可以使用這些路由。這是經過使用 @dojo/framework/widget-core/Registry 中的 Registry,定義一個將 invalidator 鏈接到 router 的 nav 事件的注入器,並返回 router 實例實現的。這裏使用 key 來定義注入器,路由器的默認 key 值爲 router

import { Registry } from '@dojo/framework/widget-core/Registry';
import { Injector } from '@dojo/framework/widget-core/Injector';

const registry = new Registry();

// 假設咱們有一個可用的 router 實例
registry.defineInjector('router', () => {
    router.on('nav', () => invalidator());
    return () => router;
};

注意: 路由提供了 註冊 router 的快捷方法

最後,爲了讓應用程序中的全部部件都能使用 registry,須要將其傳給 vdom renderer.mount() 方法。

const r = renderer(() => v(App, {}));
r.mount({ registry });

History Managers

路由自帶三個歷史管理器,用於監視和更改導航狀態:HashHistoryStateHistoryMemoryHistory。默認使用 HashHistory,可是可在建立 Router 時傳入不一樣的 HistoryManager

const router = new Router(config, { HistoryManager: MemoryHistory });
Hash History

基於哈希的管理器使用片斷標識符(fragment identifier)來存儲導航狀態,是 @dojo/framework/routing 中的默認管理器。

import { Router } from '@dojo/framework/routing/Router';
import { HashHistory } from '@dojo/framework/routing/history/HashHistory';

const router = new Router(config, { HistoryManager: HashHistory });

歷史管理器有 currentset(path: string)prefix(path: string) 三個API。HashHistory 類假定全局對象是瀏覽器的 window 對象,但能夠顯式提供對象。管理器使用 window.location.hashhashchange 事件的事件監聽器。current 訪問器返回當前路徑,不帶 # 前綴。

State History

基於狀態的歷史管理器使用瀏覽器的 history API:pushState()replaceState(),來添加和修改歷史紀錄。狀態歷史管理器須要服務器端支持纔能有效工做。

Memory History

MemoryHistory 不依賴任何瀏覽器 API,而是保持其自身的內部路徑狀態。不要在生產應用程序中使用它,但在測試路由時卻頗有用。

import { Router } from '@dojo/framework/routing/Router';
import { MemoryHistory } from '@dojo/framework/routing/history/MemoryHistory';

const router = new Router(config, { HistoryManager: MemoryHistory });

Outlet Event

當每次進入或離開 outlet 時,都會觸發 router 實例的 outlet 事件。outlet 上下文、enterexit 操做都會傳給事件處理函數。

router.on('outlet', ({ outlet, action }) => {
    if (action === 'enter') {
        if (outlet.id === 'my-outlet') {
            // do something, perhaps fetch data or set state
        }
    }
});

Router Context Injection

RouterInjector 模塊導出一個幫助函數 registerRouterInjector,它組合了 Router 實例的實例化,註冊 router 配置信息和爲提供的 registry 定義注入器,而後返回 router 實例。

import { Registry } from '@dojo/framework/widget-core/Registry';
import { registerRouterInjector } from '@dojo/framework/routing/RoutingInjector';

const registry = new Registry();
const router = registerRouterInjector(config, registry);

可以使用 RouterInjectiorOptions 覆蓋默認值:

import { Registry } from '@dojo/framework/widget-core/Registry';
import { registerRouterInjector } from '@dojo/framework/routing/RoutingInjector';
import { MemoryHistory } from './history/MemoryHistory';

const registry = new Registry();
const history = new MemoryHistory();

const router = registerRouterInjector(config, registry, { history, key: 'custom-router-key' });

Outlets

路由集成的一個基本概念是 outlet,它是與註冊的應用程序 route 關聯的惟一標識符。Outlet 是一個標準的 dojo 部件,可在應用程序的任何地方使用。Outlet 部件有一個精簡的 API:

  • id: 匹配時執行 renderer 的 outlet 標識。
  • renderer: 當 outlet 匹配時調用的渲染函數。
  • routerKey (可選): 在 registry 中定義路由時使用的 key - 默認爲 router

接收渲染的 outlet 名稱和一個 renderer 函數,當 outlet 匹配時,該函數返回要渲染的 DNode

render() {
    return v('div', [
        w(Outlet, { id: 'my-outlet', renderer: () => {
            return w(MyWidget, {});
        }})
    ])
}

可爲 renderer 函數傳入 MatchDetails 參數,該參數提供路由專有信息,用於肯定要渲染的內容和計算傳入部件的屬性值。

interface MatchDetails {
    /**
     * Query params from the matching route for the outlet
     */
    queryParams: Params;

    /**
     * Params from the matching route for the outlet
     */
    params: Params;

    /**
     * Match type of the route for the outlet, either `index`, `partial` or `error`
     */
    type: MatchType;

    /**
     * The router instance
     */
    router: RouterInterface;

    /**
     * Function returns true if the outlet match was an `error` type
     */
    isError(): boolean;

    /**
     * Function returns true if the outlet match was an `index` type
     */
    isExact(): boolean;
}
render() {
    return v('div', [
        w(Outlet, { id: 'my-outlet', renderer: (matchDetails: MatchDetails) => {
            if (matchDetails.isError()) {
                return w(ErrorWidget, {});
            }
            if (matchDetails.isExact()) {
                return w(IndexWidget, { id: matchDetails.params.id });
            }
            return w(OtherWidget, { id: matchDetails.params.id });
        }})
    ])
}

Global Error Outlet

只要註冊了一個 error 匹配類型,就會自動爲匹配的 outlet 添加一個全局 outlet,名爲 errorOutlet。這個 outlet 用於爲任何未知的路由渲染一個部件。

render() {
    return w(Outlet, {
        id: 'errorOutlet',
        renderer: (matchDetails: MatchDetails) => {
            return w(ErrorWidget, properties);
        }
    });
}

Link

Link 組件是對 DOM 節點 a 的封裝,容許用戶爲建立的連接指定一個 outlet。也能夠經過將 isOutlet 屬性值設置爲 false 來使用靜態路由。

若是生成的連接須要指定在 route 中不存在的路徑或查詢參數,可以使用 params 屬性傳入。

import { Link } from '@dojo/framework/routing/Link';

render() {
    return v('div', [
        w(Link, { to: 'foo', params: { foo: 'bar' }}, [ 'Link Text' ]),
        w(Link, { to: '#/static-route', isOutlet: false, [ 'Other Link Text' ])
    ]);
}

全部標準的 VNodeProperties 均可用於 Link 組件,由於最終是使用 @dojo/framework/widget-core 中的 v() 來建立一個 a 元素。

ActiveLink

ActiveLink 組件是對 Link 組件的封裝,若是連接處於激活狀態,則能夠爲 a 節點設置樣式類。

import { ActiveLink } from '@dojo/framework/routing/ActiveLink';

render() {
    return v('div', [
        w(ActiveLink, { to: 'foo', params: { foo: 'bar' }, activeClasses: [ 'link-active' ]}, [ 'Link Text' ])
    ]);
}
相關文章
相關標籤/搜索