介绍
Dojo 的路由包为 Web 应用程序提供了一流的声明式路由解决方案。小部件是 Dojo 应用程序中的基本概念,路由也不例外。Dojo 路由提供了一组小部件,它们直接集成到 Dojo 应用程序中,并使应用程序小部件能够与路由相关联,而不会影响其功能、可重用性或属性接口。
功能 | 描述 |
---|---|
多个历史管理器 | 路由提供了一组历史管理器,具体取决于应用程序的需求 |
开箱即用的路由小部件 | 有一组开箱即用的路由小部件,例如 Link 和 ActiveLink |
自动代码拆分 | 结合 @dojo/cli-build-app ,顶级路由会自动进行代码拆分 |
基本用法
将路由添加到应用程序
- 添加一个初始路由配置,该配置定义一个映射到路由标识符和
outlet
名称的单个 URL 路径。
src/routes.ts
export default [
{
id: 'home',
path: 'home',
outlet: 'main'
},
{
id: 'about',
path: 'about',
outlet: 'main'
},
{
id: 'profile',
path: 'profile',
outlet: 'main'
}
];
- 通过将路由器注册到应用程序注册表中,将应用程序配置为路由感知。
src/main.tsx
import renderer, { tsx } from '@dojo/framework/core/vdom';
import Registry from '@dojo/framework/core/Registry';
import { registerRouterInjector } from '@dojo/framework/routing/RouterInjector';
import routes from './routes';
import App from './App';
const registry = new Registry();
// creates a router with the routes and registers the router with the registry
registerRouterInjector(routes, registry);
const r = renderer(() => <App />);
r.mount({ registry });
- 添加一个
Route
小部件,当访问home
路由时显示文本“主页”。Route
是一个小部件,当匹配路由 ID 的路径时,它会显示一些内容。应用程序的src/routes.ts
文件通过Route
的id
属性将路由与 ID 关联起来。
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import Route from '@dojo/framework/routing/Route';
const factory = create();
export default factory(function App() {
return (
<div>
<Route id="home" renderer={() => <div>Home</div>} />
<Route id="about" renderer={() => <div>About</div>} />
<Route id="profile" renderer={() => <div>Profile</div>} />
</div>
);
});
或者使用出口和 Outlet
小部件,查看 Outlet
文档 以获取更多信息
import { create, tsx } from '@dojo/framework/core/vdom';
import Outlet from '@dojo/framework/routing/Outlet';
const factory = create();
export default factory(function App() {
return (
<div>
<Outlet id="main">
{{
home: <div>Home</div>,
about: <div>About</div>,
profile: <div>Profile</div>
}}
</Outlet>
</div>
);
});
- 路由的 URL 由路由配置的
path
元素确定。在本例中,指定了home
,因此可以通过 URL 路径/#home
访问该路由。- 默认情况下,路由器使用 HashHistory 历史管理器,该管理器需要在路由路径之前使用
#
。其他 历史管理器 可用于支持其他历史管理机制。
- 默认情况下,路由器使用 HashHistory 历史管理器,该管理器需要在路由路径之前使用
路径和查询参数
路径参数是路由配置中的占位符,将匹配该段的任何值。参数使用花括号定义,例如:{param}
。
src/routes.ts
export default [
{
id: 'home',
path: 'home/{page}',
outlet: 'home'
}
];
参数值将注入到匹配的 Route
的 renderer
属性中。
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import Route from '@dojo/framework/routing/Route';
const factory = create();
export default factory(function App() {
return (
<div>
<Route id="home" renderer={(matchDetails) => <div>{`Home ${matchDetails.params.page}`}</div>} />
</div>
);
});
查询参数也可以添加到路由 URL 中。与正常的查询参数一样,第一个查询参数必须以 ?
为前缀,其他查询参数以 &
字符分隔。请注意,在使用查询参数时,路由配置不会改变。
src/routes.ts
export default [
{
id: 'home',
path: 'home/{page}?{queryOne}&{queryTwo}',
outlet: 'home'
}
];
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import Route from '@dojo/framework/routing/Route';
const factory = create();
export default factory(function App() {
return (
<div>
<Route
id="home"
renderer={(matchDetails) => {
const { queryParams } = matchDetails;
return <div>{`Home ${queryParams.queryOne}-${queryParams.queryTwo}`}</div>;
}}
/>
</div>
);
});
如果浏览器指向 URL 路径 /home/page?queryOne=modern&queryTwo=dojo
,则查询参数将作为 MatchDetails
类型的对象注入到匹配的 Route
的 renderer
方法中,并通过该对象的 queryParams
属性访问。使用此 URL,页面将显示“Hello modern-dojo”。如果未提供查询参数,则其值将设置为 undefined
。
可选查询参数
路径参数始终是必需的,因为它们是路由路径的一部分,但查询参数有时可能是可选的。要定义可选查询参数,请在查询参数的结束括号之前添加 ?
。这指示路由器即使未提供此参数的值也能生成链接。
src/routes.ts
export default [
{
id: 'home',
path: 'home?{page?}',
outlet: 'home'
}
];
在本例中,page
现在是可选的,这意味着路由器可以在没有 page 值的情况下生成链接,并且查询参数将不会添加到 URL 中。
默认路由和参数
- 通过更新路由配置以在首选路由中包含
defaultRoute: true
来指定默认路由。如果未提供任何路由或未注册请求的路由,则默认路由用于在初始加载时重定向应用程序。
src/routes.ts
export default [
{
id: 'home',
path: 'home',
outlet: 'home',
defaultRoute: true
}
];
如果默认路由具有路径或查询参数,则需要指定一个默认值的映射。
src/routes.ts
export default [
{
id: 'home',
path: 'home/{page}',
outlet: 'home',
defaultRoute: true,
defaultParams: {
page: 'about'
}
}
];
通配符路由
*
字符可用于指示通配符路由。路由将正常匹配,直到 *
,并且将匹配该点的任何路径。通配符路由永远不会优先于没有通配符的其他匹配路由。*
隐式指示匹配的结束,并且在路由配置中 *
之后指定的任何段都将被忽略。实际 URL 中的任何其他段都将与 matchDetails
中名为 wildcardSegments
的数组属性一起传递。
export default [
{
id: 'catchall',
// Anything after the asterisk will be ignored in this config
path: '*',
outlet: 'catchall'
},
// This path will be preferred to the wildcard as long as it matches
{
id: 'home',
path: 'home',
outlet: 'home'
}
];
*
之后和包括匹配的 *
在内的所有段都将作为 wildcardSegments
注入到匹配的 Route
的 renderer
属性中。
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import Route from '@dojo/framework/routing/Route';
const factory = create();
export default factory(function App() {
return (
<div>
<Route id="home" renderer={(matchDetails) => <div>{`Home ${matchDetails.params.page}`}</div>} />
<Route
id="catchall"
renderer={(matchDetails) => <div>{`Matched Route ${matchDetails.wildcardSegments.join(', ')}`}</div>}
/>
</div>
);
});
使用链接小部件
Link
小部件是锚标记的包装器,它使使用者能够指定路由 id
来创建指向该路由的链接。如果生成的链接需要路由中没有的特定路径或查询参数,则可以通过 params
属性传递它们。
链接属性
to: string
:route
ID。params: { [index: string]: string }
: 用于生成链接的路由参数。onClick: (event: MouseEvent) => void
(可选):单击Link
时调用的函数。
除了 Link
特定属性之外,所有标准 VNodeProperties
都可用于 Link
小部件,因为它们会创建锚标记。
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { Link } from '@dojo/framework/routing/Link';
const factory = create();
export default factory(function App() {
return (
<div>
<Link to="home" params={{ foo: 'bar' }}>
Link Text
</Link>
</div>
);
});
ActiveLink
小部件是 Link
小部件的包装器,如果链接当前处于活动状态,它会在 a
节点上条件地设置类。
ActiveLink 属性
activeClasses: string[]
: 当匹配Link
的路由时要应用的类数组。
import { create, tsx } from '@dojo/framework/core/vdom';
import { ActiveLink } from '@dojo/framework/routing/ActiveLink';
const factory = create();
export default factory(function App() {
return (
<div>
<ActiveLink to="home" params={{ foo: 'bar' }} activeClasses={['link-active']}>
Link Text
</ActiveLink>
</div>
);
});
按路由代码拆分
当使用 @dojo/cli-build-app
时,Dojo 默认情况下支持对所有顶级路由进行自动代码拆分。这意味着 Route
的 renderer
中引用的所有小部件都将包含该路由的特定捆绑包,该捆绑包将在用户访问该路由时延迟加载。
要利用代码拆分,有 4 个规则
- 路由配置需要是
src/routes.ts
模块中的默认导出。 - 小部件必须是其模块的默认导出。
renderer
属性必须内联定义。- 路由配置中的
id
和outlet
必须是静态的,并且内联定义。
src/routes.ts
export default [
{
id: 'home',
path: 'home',
outlet: 'home'
},
{
id: 'about',
path: 'about',
outlet: 'about',
children: [
{
id: 'company',
path: 'company',
outlet: 'about-company'
}
]
},
{
id: 'profile',
path: 'profile',
outlet: 'profile'
},
{
id: 'settings',
path: 'settings',
outlet: 'settings'
}
];
使用上面的路由配置,以下示例将为 Route
的渲染器中返回的每个小部件生成 4 个单独的捆绑包,Home
、About
、Profile
和 Settings
。
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import Route from '@dojo/framework/routing/Route';
import Home from './Home';
import About from './About';
import Profile from './Profile';
import Settings from './Settings';
const factory = create();
export default factory(function App() {
return (
<div>
<Route id="home" renderer={() => <Home />} />
<Route id="about" renderer={() => <About />} />
<Route id="profile" renderer={() => <Profile />} />
<Route id="settings" renderer={() => <Settings />} />
</div>
);
});