React 导航
本指南将介绍在基于 Ionic 和 React 构建的应用中,路由是如何工作的。
IonReactRouter 底层使用了流行的 React Router 库。借助 Ionic 和 React Router,你可以创建具有丰富页面转场效果的多页面应用。
你在 React Router 中学到的所有路由知识都可以直接应用于 Ionic React。让我们先来了解一下 Ionic React 应用的基础知识以及路由是如何与之协同工作的。
Ionic React 中的路由
下面是一个简单的 App 组件示例,它定义了一条指向 "/dashboard" URL 的路由。当访问 "/dashboard" 时,该路由会渲染 DashboardPage 组件。
App.tsx
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route path="/dashboard" component={DashboardPage} />
<Redirect exact from="/" to="/dashboard" />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
在 Route 之后,我们定义了一个默认的 Redirect。当用户访问应用的根 URL ("/") 时,它会将用户重定向到 "/dashboard" URL。
这个重定向还设置了 exact 属性,这意味着 URL 必须与 from 属性(或者如果 Route 上使用了 exact,则是 path 属性)精确匹配,该路由才会生效。如果没有 exact,由于所有路由都以 "/" 开头,这个重定向将会为每个路由渲染。
你也可以根据条件(例如检 查用户是否已认证)在 Route 的 render 方法中进行编程式重定向:
<Route
exact
path="/dashboard"
render={(props) => {
return isAuthed ? <DashboardPage {...props} /> : <LoginPage />;
}}
/>
IonReactRouter
IonReactRouter 组件是对 React Router 中传统的 BrowserRouter 组件的封装,它为应用设置了路由环境。因此,请使用 IonReactRouter 来替代 BrowserRouter。你可以向 IonReactRouter 传递任何属性,这些属性都将被传递给底层的 BrowserRouter。
嵌套路由
在 Dashboard 页面内部,我们可以为应用的这一特定部分定义更多相关的路由:
DashboardPage.tsx
const DashboardPage: React.FC = () => {
return (
<IonPage>
<IonRouterOutlet>
<Route exact path="/dashboard" component={UsersListPage} />
<Route path="/dashboard/users/:id" component={UserDetailPage} />
</IonRouterOutlet>
</IonPage>
);
};
这里,我们定义了另外几个路由,用于指向 Dashboard 区域内的不同页面。注意,我们需要在路径中定义完整的路由,即使我们已经从该 URL 进入了此页面,也不能省略 "/dashboard" 部分。React Router 要求使用完整路径,不支持相对路径。
不过,我们可以利用 match 对象的 url 属性来获取用于渲染组件的匹配 URL,这在处理嵌套路由时会很有帮助:
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonPage>
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
</IonRouterOutlet>
</IonPage>
);
};
在这里,match.url 的值是 "/dashboard",因为正是这个 URL 被用来渲染 DashboardPage。
这些路由被分组在一个 IonRouterOutlet 中,接下来我们就来讨论它。
IonRouterOutlet
IonRouterOutlet 组件为渲染 Ionic "页面" 的路由提供了一个容器。当一个页面位于 IonRouterOutlet 内时,该容器不仅会控制页面之间的转场动画,还会管理页面的创建和销毁时机。这有助于在视图间来回切换时,保持之前页面的状态。
上面的 DashboardPage 展示了一个用户列表页和一个详情页。当在这两个页面之间导航时,IonRouterOutlet 会提供适合平台的页面转场效果,并保留前一个页面的状态。这样,当用户返回列表页时,它会保持与离开时相同的状态。
一个 IonRouterOutlet 应该只包含 Route 或 Redirect。任何其他组件都应该作为 Route 渲染的结果来呈现,或者放在 IonRouterOutlet 之外。
默认路由(404 处理)
一个常见的路由需求是提供一个“默认”或“后备”路由,以便在用户导航到未定义的路由时呈现。
我们可以通过将不带 path 属性的 Route 组件作为 IonRouterOutlet 中的最后一个路由来实现。
DashboardPage.tsx
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
<Route render={() => <Redirect to={match.url} />} />
</IonRouterOutlet>
);
};
如上所示,如果访问的路径与前两个 Route 都不匹配,IonRouterOutlet 会将 Ionic React 应用重定向到 match.url 路径。
你也可以提供一个要渲染的组件,而不是进行重定向。
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
<Route component={NotFoundPage} />
</IonRouterOutlet>
);
};
IonPage
IonPage 组件包裹着 Ionic React 应用中的每个视图,确保页面转场和堆栈导航能正常工作。任何通过路由导航到的视图都必须包含一个 IonPage 组件。
IonPage 对于正确的样式也是必需的。它提供了一个 Flex 容器,确保页面内容(如 IonContent)能够正确调整大小,并且不会与其他 UI 元素(如 IonTabBar)重叠。
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>首页</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">你好,世界</IonContent>
</IonPage>
);
};
export default Home;
导航
在 Ionic React 应用中,有多种方式可以导航到不同的视图。这里,UsersListPage 使用 IonItem 的 routerLink 属性来指定点击项目时要跳转的路由:
UsersListPage.tsx
const UsersListPage: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>用户</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonList>
<IonItem routerLink="/dashboard/users/1">
<IonLabel>用户 1</IonLabel>
</IonItem>
<IonItem routerLink="/dashboard/users/2">
<IonLabel>用户 2</IonLabel>
</IonItem>
</IonList>
</IonContent>
</IonPage>
);
};
其他支持 routerLink 属性的组件还包括 IonButton、IonCard、IonRouterLink、IonFabButton 和 IonItemOption。
这些组件也都有一个 routerDirection 属性,用于明确设置页面转场的类型(可选值为 "forward"、"back" 或 "root")。
除了这些带有 routerLink 属性的组件,你也可以使用 React Router 的 Link 组件在视图间导航:
<Link to="/dashboard/users/1">用户 1</Link>
只要情况允许,我们推荐优先使用上述方法进行路由。这样做的好处是它们都会渲染成一个锚点(<a>)标签,这对于提升应用的整体可访问性非常有利。
编程式导航的选项是使用 React Router 通过路由传递给组件的 history 属性。
<IonButton
onClick={(e) => {
e.preventDefault();
history.push('/dashboard/users/1');
}}
>
前往用户 1
</IonButton>
history 是一个属性 (prop)。
使用 history.go 进行导航
React Router 使用了 history 包,它提供了一个 history.go 方法,允许开发者在应用历史记录中向前或向后移动。让我们看一个例子。
假设你有以下应用历史记录:
/pageA --> /pageB --> /pageC
如果你在 /pageC 上调用 router.go(-2),你会被带回到 /pageA。如果你之后再调用 router.go(2)