介绍

Dojo 的路由包为 web 应用程序提供了一流的声明式路由解决方案。部件是 Dojo 应用程序的基本概念,路由并不会影响部件的使用方式。Dojo 路由提供了一组部件,可直接在 Dojo 应用程序中使用,让应用程序的部件与路由关联,却不会影响其功能、可重用性和属性接口。

功能描述
支持多个历史管理器路由提供了一组历史选择器,可根据应用程序的实际需要选择
现成的路由部件有几个现成的路由部件,如 LinkActiveLink
自动化代码拆分@dojo/cli-build-app 结合使用,会自动按顶级路由进行代码拆分

基本用法

为应用程序添加路由

  • 添加一个初始的路由配置,该配置定义一个 url 路径,然后映射到一个路由标识符和 outlet 上。

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home',
  5. outlet: 'main'
  6. },
  7. {
  8. id: 'about',
  9. path: 'about',
  10. outlet: 'main'
  11. },
  12. {
  13. id: 'profile',
  14. path: 'profile',
  15. outlet: 'main'
  16. }
  17. ];
  • 使用应用程序注册器(registry)注册路由,让应用程序支持路由。

src/main.tsx

  1. import renderer, { tsx } from '@dojo/framework/core/vdom';
  2. import Registry from '@dojo/framework/core/Registry';
  3. import { registerRouterInjector } from '@dojo/framework/routing/RouterInjector';
  4. import routes from './routes';
  5. import App from './App';
  6. const registry = new Registry();
  7. // creates a router with the routes and registers the router with the registry
  8. registerRouterInjector(routes, registry);
  9. const r = renderer(() => <App />);
  10. r.mount({ registry });
  • 添加一个 Route 部件,当访问 home 路由时显示文本“Home”。Route 也是部件,当路由标识与路径匹配时用于显示一些内容。Route 部件的 id 属性与应用程序 src/routes.ts 文件中的 id 属性要关联起来。

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import Route from '@dojo/framework/routing/Route';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <Route id="home" renderer={() => <div>Home</div>} />
  8. <Route id="about" renderer={() => <div>About</div>} />
  9. <Route id="profile" renderer={() => <div>Profile</div>} />
  10. </div>
  11. );
  12. });

或者使用 Outlet 部件,查看 Outlet 文档了解更多信息:

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import Outlet from '@dojo/framework/routing/Outlet';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <Outlet id="main">
  8. {{
  9. home: <div>Home</div>,
  10. about: <div>About</div>,
  11. profile: <div>Profile</div>
  12. }}
  13. </Outlet>
  14. </div>
  15. );
  16. });
  • 路由的 URL 是由路由配置中的 path 元素决定的。在本例中,path 的值为 home,所以使用 URL 路径 /#home 可以访问此路由。
    • 默认情况下,路由使用 HashHistory 作为历史管理器,该管理器要求在路由路径前加上 #。其他历史管理器可用于支持其他历史管理器的应用场景。

路径和查询参数

路由参数是路由配置中的占位符,可为该段匹配任意值。参数是由大括号定义的,例如:{param}

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home/{page}',
  5. outlet: 'home'
  6. }
  7. ];

参数值会被注入到匹配的 Routerenderer 属性中。

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import Route from '@dojo/framework/routing/Route';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <Route id="home" renderer={(matchDetails) => <div>{`Home ${matchDetails.params.page}`}</div>} />
  8. </div>
  9. );
  10. });

查询参数也可以添加到路由的 URL 中。与普通的查询参数一样,第一个参数的前缀必须是 ?,参数间使用 & 字符分隔。注意,当使用查询参数时,路由配置无需调整。

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home/{page}?{queryOne}&{queryTwo}',
  5. outlet: 'home'
  6. }
  7. ];

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import Route from '@dojo/framework/routing/Route';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <Route
  8. id="home"
  9. renderer={(matchDetails) => {
  10. const { queryParams } = matchDetails;
  11. return <div>{`Home ${queryParams.queryOne}-${queryParams.queryTwo}`}</div>;
  12. }}
  13. />
  14. </div>
  15. );
  16. });

如果浏览器指向的 URL 路径为 /home/page?queryOne=modern&queryTwo=dojo,那么查询字符串就会被注入到匹配的 Routerenderer 方法,该注入的对象属于 MatchDetails 类型,可通过此对象的 queryParams 属性访问。使用此 URL,页面将显示“Hello modern-dojo”。如果没有提供查询参数,那么它的值将被设置为 undefined

默认的路由和参数

  • 更新路由配置,为首选路由添加 defaultRoute: true 以指定为默认路由。如果没有提供路由或者请求的路由未注册,则应用程序初始化时会跳转到默认路由。

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home',
  5. outlet: 'home',
  6. defaultRoute: true
  7. }
  8. ];

如果默认路由中有路径参数或查询参数,则需要指定默认值。

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home/{page}',
  5. outlet: 'home',
  6. defaultRoute: true,
  7. defaultParams: {
  8. page: 'about'
  9. }
  10. }
  11. ];

使用 Link 部件

Link 部件是对 anchor 标签的封装,让用户创建一个指向路由 id 的超链接。如果生成的超链接需要指定路径参数或查询参数,则可以通过 params 参数传入。

Link 属性:

  • to: string:对应 route 的 id。
  • params: { [index: string]: string }:为路由生成超链接时传入的参数。
  • onClick: (event: MouseEvent) => void (可选):单击 Link 部件时调用的函数。

除了 Link 专有属性外,在创建 anchor 标签时,所有标准的 VNodeProperties 也都可设置给 Link 部件。

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import { Link } from '@dojo/framework/routing/Link';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <Link to="home" params={{ foo: 'bar' }}>
  8. Link Text
  9. </Link>
  10. </div>
  11. );
  12. });

ActiveLink 部件是对 Link 部件的封装,如果链接处于激活状态,则会设置 a 节点上的样式类:

ActiveLink 属性:

  • activeClasses: string[]:一组样式类,当 Link 的路由匹配时会应用这些样式。
  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import { ActiveLink } from '@dojo/framework/routing/ActiveLink';
  3. const factory = create();
  4. export default factory(function App() {
  5. return (
  6. <div>
  7. <ActiveLink to="home" params={{ foo: 'bar' }} activeClasses={['link-active']}>
  8. Link Text
  9. </ActiveLink>
  10. </div>
  11. );
  12. });

按路由拆分代码

当使用 @dojo/cli-build-app 时,Dojo 默认支持为所有顶层路由进行自动化代码拆分。这意味着 Routerenderer 中引用的所有部件都会包含在该路由专有包中,当用户访问此路由时会延迟加载。

要使用代码拆分功能,需遵循以下 4 条规则:

  1. 路由配置必须是从 src/routes.ts 模块中默认导出。
  2. 部件必须是其所属模块的默认导出。
  3. renderer 属性必须是内联定义的。
  4. 路由配置中的 idoutlet 必须是静态的,并且是内联定义的。

src/routes.ts

  1. export default [
  2. {
  3. id: 'home',
  4. path: 'home',
  5. outlet: 'home'
  6. },
  7. {
  8. id: 'about',
  9. path: 'about',
  10. outlet: 'about',
  11. children: [
  12. {
  13. id: 'company',
  14. path: 'company',
  15. outlet: 'about-company'
  16. }
  17. ]
  18. },
  19. {
  20. id: 'profile',
  21. path: 'profile',
  22. outlet: 'profile'
  23. },
  24. {
  25. id: 'settings',
  26. path: 'settings',
  27. outlet: 'settings'
  28. }
  29. ];

使用上面的路由配置,以下示例将为 Route 的渲染函数返回的部件生成 4 个单独的包,这 4 个部件分别是 HomeAboutProfileSettings

src/App.tsx

  1. import { create, tsx } from '@dojo/framework/core/vdom';
  2. import Route from '@dojo/framework/routing/Route';
  3. import Home from './Home';
  4. import About from './About';
  5. import Profile from './Profile';
  6. import Settings from './Settings';
  7. const factory = create();
  8. export default factory(function App() {
  9. return (
  10. <div>
  11. <Route id="home" renderer={() => <Home />} />
  12. <Route id="about" renderer={() => <About />} />
  13. <Route id="profile" renderer={() => <Profile />} />
  14. <Route id="settings" renderer={() => <Settings />} />
  15. </div>
  16. );
  17. });