This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
Expo Router 中常见的导航模式
将 Expo Router 基础知识应用于你可以在应用中使用的实际导航模式。
现在你已经了解了 Expo Router 中文件和目录的命名和排列方式,让我们运用这些知识,看看你可能在应用中使用的一些实际导航模式。
🌐 Now that you know the basics of how files and directories are named and arranged in Expo Router, let's apply that knowledge, looking at some real-life navigation patterns you might use in your app.
标签页内的堆栈:嵌套导航器
🌐 Stacks inside tabs: nested navigators
如果你的应用的典型起点是一组标签页,但一个或多个标签页可能对应多个屏幕,那么在标签页内嵌套堆栈导航器通常是可行的。这种模式通常会产生直观的 URL,并且在桌面 Web 应用中扩展良好,因为主要的标签页通常始终可见。
🌐 If the typical starting point for your app is a set of tabs, but one or more tabs may have more than one screen associated with it, nesting a stack navigator inside of a tab is often the way to go. This pattern often results in intuitive URLs and scales well to desktop web apps, where the primary tabs are often always visible.
考虑以下导航树:
🌐 Consider the following navigation tree:
srcapp(tabs)_layout.tsxindex.tsxsingle page tabfeed_layout.tsxtab with a stack insideindex.tsx[postId].tsxsettings.tsxsingle page tab在 src/app/(tabs)/_layout.tsx 文件中,返回一个 Tabs 组件:
🌐 In the src/app/(tabs)/_layout.tsx file, return a Tabs component:
在 src/app/(tabs)/feed/_layout.tsx 文件中,返回一个 Stack 组件:
🌐 In the src/app/(tabs)/feed/_layout.tsx file, return a Stack component:
现在,在 src/app/(tabs)/feed 目录下,你可以有指向不同帖子(例如 /feed/123)的 Link 组件。这些链接会将 feed/[postId] 路由推入堆栈,同时保持选项卡导航器可见。
🌐 Now, within the src/app/(tabs)/feed directory, you can have Link components that point to different posts (for example, /feed/123). Those links will push the feed/[postId] route onto the stack, leaving the tab navigator visible.
你也可以从任何其他标签页通过相同的 URL 导航到 feed 标签页中的帖子。将 withAnchor 与 anchor 配合使用,以确保 feed/index 路由始终是堆栈中的第一个屏幕:
🌐 You can also navigate from any other tab to a post in the feed tab with the same URL. Use withAnchor in conjunction with anchor to ensure that the feed/index route is always the first screen in the stack:
你也可以在外部堆栈导航器中嵌套标签页。这在需要在标签页上方显示模态窗口时通常更有用。
🌐 You can also nest tabs inside of an outer stack navigator. That is often more useful for displaying modals over the tabs.
回到你来的标签页
🌐 Going back to the tab you came from
点击属于另一个标签页的 URL 的 Link 会切换标签页,然后返回按钮会弹出该标签页内的堆栈。在上面的例子中,从设置标签页打开 /feed/123 会跳转到 Feed 标签页的帖子。点击返回会回到 feed/index,而不是设置页。
🌐 A Link to a URL that belongs to another tab switches tabs, and the back button then pops the stack inside that tab. In the example above, opening /feed/123 from the Settings tab lands on the post in the Feed tab. Going back returns to feed/index, not to Settings.
使用 native tabs 时,标签导航器在挂载时会立即加载每个标签。包含堆栈的标签在你链接进去之前就已经处于该堆栈的第一个屏幕。无论你是否传入 withAnchor,该屏幕最终都会出现在你链接的屏幕下面。
🌐 With native tabs, the tab navigator loads every tab as soon as it mounts. A tab that contains a stack is already sitting at that stack's first screen before you link into it. That screen ends up underneath the one you linked to whether or not you pass withAnchor.
如果你希望返回按钮能回到你之前的屏幕,就把详情路由放在 tab 外,从外层的 stack 推入它:
🌐 If you want the back button to return to the screen you came from, keep the detail route out of the tabs and push it from an outer stack instead:
srcapp_layout.tsxstack that contains the tabs(tabs)_layout.tsxindex.tsxfeed_layout.tsxindex.tsxsettings.tsxfeed[postId].tsxpushed above the tab bar/feed/123 现在是根堆栈的一个屏幕,而不是 Feed 标签的屏幕。路由会把它推到当前打开的标签上,返回则会回到该标签。这也是 iOS 应用中详情屏幕通常的表现方式。
了解更多关于如何在你的 Expo Router 应用中使用嵌套导航器的信息。
不同平台的标签:平台特定的标签
🌐 Different tabs per platform: platform-specific tabs
在构建跨平台应用时,你可能希望在 Android 和 iOS 上使用 原生标签 以获得平台原生的外观和感觉,而在 Web 上使用 自定义标签 以完全控制样式。你可以使用 平台特定的文件扩展名 来实现这一点。
🌐 When building a cross-platform app, you may want to use native tabs on Android and iOS for a platform-native look and feel, while using custom tabs on web for full control over styling. You can achieve this using platform-specific file extensions.
srcapp_layout.tsximports AppTabsindex.tsxfeed.tsxprofile.tsxcomponentsapp-tabs.native.tsxAppTabs (native tabs) for Android and iOSapp-tabs.tsxAppTabs (custom tabs) for web根布局渲染一个 AppTabs 组件。Expo 的模块解析会在 Android 和 iOS 上自动选择 app-tabs.native.tsx,在 web 上选择 app-tabs.tsx,从而允许每个平台使用符合其惯例的选项卡实现。
🌐 The root layout renders an AppTabs component. Expo's module resolution automatically picks app-tabs.native.tsx on Android and iOS, and app-tabs.tsx on web, allowing each platform to use a tab implementation suited to its conventions.
有关此模式的完整代码示例,请参阅布局指南中的特定平台的选项卡。
🌐 For a complete example of this pattern with code, see Platform-specific tabs in the Layout guide.
一个屏幕,两个标签:分享路由
🌐 One screen, two tabs: sharing routes
路由组可以用来在两个不同的标签之间共享一个屏幕。考虑一个导航树,它有一个“动态”标签和一个“搜索”标签,并且它们都共享用于查看用户资料的页面:
🌐 Route groups can be used to share a single screen between two different tabs. Consider a navigation tree that has a Feed tab and a Search tab, and they both share pages for viewing a user profile:
srcapp(tabs)_layout.tsx(feed)index.tsxdefault route(search)search.tsx(feed,search)_layout.tsxlayout shared between the two tabsusers[username].tsxshared user profile page每个选项卡都被放在一个组中,因此你可以定义一个第三个目录,在两个组之间共享路由(src/app/(tabs)/(feed,search)/)。即使有了额外的层次,src/app/(tabs)/(feed)/index.tsx 仍然是最近的索引文件,因此它将是默认路由。
🌐 Each of the tabs is put in a group so you can define a third directory that shares routes between two groups (src/app/(tabs)/(feed,search)/). Even with the extra layer, src/app/(tabs)/(feed)/index.tsx is still the nearest index, so it will be the default route.
(feed) 和 (search) 路由组都包含堆栈,因此它们也可以共享一个布局:
🌐 Both the (feed) and (search) route groups contain stacks, so they can also share a single layout:
共享组也可以仅包含共享页面,每个不同的组都有自己的布局文件。
🌐 It's also possible for shared groups to only contain the shared pages, with each distinct group having its own layout file.
现在,两个标签页都可以导航到 /users/evanbacon 并查看相同的用户资料页面。
🌐 Now, both tabs can navigate to /users/evanbacon and see the same user profile page.
当你已经专注于一个标签页并导航到某个用户时,你将会停留在当前标签页的组中。但是,当从应用外部直接深度链接到用户个人资料页面时,Expo Router 必须选择两个组中的一个,因此它会选择按字母顺序排列的第一个组。因此,深度链接到 /users/evanbacon 将会在“信息流”标签页中显示该用户的个人资料。
🌐 When you're already focused on a tab and navigating to a user, you will stay in that current tab's group. But when deep-linking directly to a user profile page from outside the app, Expo Router has to pick one of the two groups, so it will pick the first group alphabetically. Therefore, deep-linking to /users/evanbacon will show the user profile in the Feed tab.
了解更多关于在 Expo Router 中不同路由如何共享相同 URL 的信息。
仅限已验证用户:受保护的路由
🌐 Authenticated users only: protected routes
对于需要身份验证的移动应用,你可能会有一组只能由经过身份验证的用户访问的路由。
🌐 For mobile apps requiring authentication, you will likely have a set of routes that should only be accessible to authenticated users.
例如,考虑以下导航树,其中有一个底部选项卡布局、一个登录页面、一个创建账户页面和一个仅对经过身份验证的用户可见的模态窗口:
🌐 For example, consider the following navigation tree in which you have a bottom tabs layout, a sign-in page, a create account page, and a modal that should only be visible to authenticated users:
srcapp_layout.tsxRoot layout(tabs)_layout.tsxindex.tsxProtected settings.tsxProtected sign-in.tsxcreate-account.tsxmodal.tsxProtected 当你的应用首次启动时,路由会尝试打开根索引 src/app/(tabs)/index.tsx。如果你将此屏幕用 Stack.Protected 封装并添加 guard={false},该屏幕将变得无法访问,取而代之的是下一个可用的屏幕将被打开。在这个示例中,将打开 sign-in 屏幕,因为它是下一个可用的路由。
🌐 When your app is first launched, the router will try to open the root index, src/app/(tabs)/index.tsx. If you wrap this screen in a Stack.Protected with the guard={false}, the screen will become inaccessible and the next available screen will be opened instead. In this example, the sign-in screen will be opened, since it is the next available route.
这样,你可以从存储中获取你的身份验证状态并显示相应的界面。如果身份验证状态发生变化,布局会重新渲染,所以如果 isLoggedIn 从 false 变为 true,应用会自动导航到 (tabs) 组的根目录。
🌐 This way, you can fetch your auth state from a store and show the appropriate screens. If the auth state changes, the layout will re-render, so if isLoggedIn changes from false to true, the app will automatically navigate to the root of the (tabs) group.
受保护路由的另一个好处是,即使直接深层链接到某个页面,它们也会被检查。例如,如果未经身份验证的用户直接深层链接到上面的模态屏幕,他们将会被重定向到登录页面。
🌐 Another benefit of protected routes is that they are checked even if you deep link into a page directly. For example, if an unauthenticated user deep links into the modal screen above, they will be redirected to the sign-in page.
受保护的路由也可以用于有条件地显示底部标签。在此示例中,只有已通过身份验证且为 VIP 会员的用户才能看到 vip 标签:
🌐 Protected routes can also be used to conditionally show bottom tabs. In this example, the vip tab will only be shown to authenticated users who are VIP members:
请参考详细指南,了解如何使用受保护路由实现身份验证。
有时最佳路由根本不是路由
🌐 Sometimes the best route isn't a route at all
将你的导航状态分离到不同的路由中是为了服务于你和你的应用。有时,最合适的模式根本不需要导航到另一个路由。由于布局文件只是 React 组件,你可以用它们来显示各种 UI,而不仅仅是导航器,或者作为导航器的补充或替代。
🌐 Separating your navigation states into distinct routes is meant to serve you and your app. Sometimes the best pattern for the job will not involve navigating to another route at all. Since layout files are just React components, you can use them to display all sorts of UI around, besides, or instead of a navigator.
回想一下认证,受保护的路由设置在用户未经登录时无法访问某些页面的情况下效果很好。但如果未认证的用户可以以只读模式浏览应用呢?在这种情况下,你可能希望在应用上显示一个登录弹窗,而不是将用户重定向到登录页面:
🌐 Thinking back to authentication, the protected route setup works great if the user should simply not be able to visit certain pages without logging in. But what about when unauthenticated users can browse an app in read-only mode? In that case, you might want to show a login modal over the app, rather than redirecting the user to a login page:
学习在 Expo Router 中显示模态窗口的多种模式,包括在布局文件中使用模态窗口。