出口
出口代表应用程序的视觉位置,根据匹配的路由渲染不同的内容。与使用路由相比,使用出口减少了所需的样板代码,多个路由可以与同一个出口关联,以更自然、更准确地构建应用程序输出。
考虑一个典型的应用程序布局,它包含一个左侧菜单和一个主内容视图,根据路由,它有一个右侧边栏。
-------------------------------------------------------------------
| | | |
| | | |
| | | |
| | | |
| | | |
| menu | main | side-menu |
| | | |
| | | |
| | | |
| | | |
| | | |
-------------------------------------------------------------------
下面的路由配置将所有主页面指定到主内容出口,但将widget
指定到side-menu
出口。这使得能够构建一个应用程序,该应用程序根据路由不断渲染主内容,但也包括widget
路由的所有子路由的右侧菜单。
const routes = [
{
id: 'landing',
path: '/',
outlet: 'main',
defaultRoute: true
},
{
id: 'widget',
path: 'widget/{widget}',
outlet: 'side-menu',
children: [
{
id: 'tests',
path: 'tests',
outlet: 'main'
},
{
id: 'overview',
path: 'overview',
outlet: 'main'
},
{
id: 'example'
path: 'example/{example}',
outlet: 'main'
}
]
}
];
在上面的路由配置中,定义了两个出口,main
和side-menu
,下面显示了一个使用出口的简化应用程序布局。默认情况下,Outlet
将渲染任何与出口匹配的路由 ID 相等的键,在本例中为main
。如果向Outlet
传递一个函数,则它将在匹配到指定出口的任何路由时渲染。
import { create, tsx } from '@dojo/framework/core/vdom';
import Outlet from '@dojo/framework/routing/Outlet';
import Menu from './Menu';
import SideMenu from './SideMenu';
import Landing from './Landing';
import Tests from './Tests';
import Example from './Example';
const factory = create();
const App = factory(function App() {
return (
<div>
<Menu />
<main>
<div>
<Outlet id="main">
{{
landing: <Landing />,
tests: <Tests />,
example: ({ params: { example }}) => <Example example={example}/>,
overview: <Example example="overview"/>
}}
</Outlet>
</div>
<div>
<Outlet id="side-menu">
{({ params: { widget }}) => <SideMenu widget={widget}>}
</Outlet>
</div>
</main>
</div>
);
});
App
的节点结构看起来很好,简洁地代表了用户实际的视觉输出,并且重复最少,但仍然需要在不同的路由中重复使用Example
小部件。这可以通过使用matcher
属性来覆盖默认的路由匹配规则来解决。matcher
接收defaultMatches
和matchDetailsMap
,以便进行自定义匹配决策。在下面的最终示例中,Example
的使用已合并到一个新的key
,details
,该key
不存在作为路由。除非我们覆盖默认匹配以在example
或overview
路由匹配时将其设置为true
,否则它永远不会与出口匹配。最后,在details
渲染器中,example
属性已默认为overview
,以保持与以前相同的行为。
import { create, tsx } from '@dojo/framework/core/vdom';
import Outlet from '@dojo/framework/routing/Outlet';
import Menu from './Menu';
import SideMenu from './SideMenu';
import Landing from './Landing';
import Tests from './Tests';
import Example from './Example';
const factory = create();
const App = factory(function App() {
return (
<div>
<Menu />
<main>
<div>
<Outlet id="main" matcher={(defaultMatches, matchDetailsMap) => {
defaultMatches.details = matchDetailsMap.has('example') || matchDetailsMap.has('overview');
return defaultMatches;
}}>
{{
landing: <Landing />,
tests: <Tests />,
details: ({ params: { example = "overview" }}) => <Example example={example}/>,
}}
</Outlet>
</div>
<div>
<Outlet id="side-menu">
{({ params: { widget }}) => <SideMenu widget={widget}>}
</Outlet>
</div>
</main>
</div>
);
});