添加导航
在本章中,了解如何向 Expo 应用添加导航。
在本章中,我们将学习 Expo Router 的基础知识,以创建堆栈导航和带有两个选项卡的底部选项卡栏。
🌐 In this chapter, we'll learn Expo Router's fundamentals to create stack navigation and a bottom tab bar with two tabs.

Expo 路由基础知识
🌐 Expo Router basics
Expo Router 是一个基于文件的 React Native 和 Web 应用路由框架。它管理屏幕之间的导航,并在多个平台上使用相同的组件。要开始使用,我们需要了解以下约定:
🌐 Expo Router is a file-based routing framework for React Native and web apps. It manages navigation between screens and uses the same components across multiple platforms. To get started, we need to know about the following conventions:
- 应用目录:一个只包含路由及其布局的特殊目录。添加到该目录的任何文件都会成为我们原生应用中的一个屏幕以及网页上的一个页面。
- 根布局:app/_layout.tsx 文件。它定义了共享的 UI 元素,如头部和选项卡栏,以确保在不同路由之间保持一致。
- 文件命名约定:Index 文件名,例如 index.tsx,与其父目录匹配,并且不添加路径段。例如,app 目录中的 index.tsx 文件对应
/路由。 - 一个 route 文件将一个 React 组件作为其默认值导出。它可以使用
.js、.jsx、.ts或.tsx扩展名。 - Android、iOS 和 Web 共享统一的导航结构。
上述列表足够我们入门。有关完整功能列表,请参见 Expo Router 介绍。
1
向堆栈中添加一个新屏幕
🌐 Add a new screen to the stack
让我们在 app 目录下创建一个名为 about.tsx 的新文件。当用户导航到 /about 路由时,它会显示屏幕名称。
🌐 Let's create a new file named about.tsx inside the app directory. It displays the screen name when the user navigates to the /about route.
import { Text, View, StyleSheet } from 'react-native'; export default function AboutScreen() { return ( <View style={styles.container}> <Text style={styles.text}>About screen</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', justifyContent: 'center', alignItems: 'center', }, text: { color: '#fff', }, });
在 app/_layout.tsx 中:
🌐 Inside app/_layout.tsx:
- 添加一个
<Stack.Screen />组件和一个options属性来更新/about路由的标题。 - 通过添加
options属性,将/index路由的标题更新为Home。
import { Stack } from 'expo-router'; export default function RootLayout() { return ( <Stack> <Stack.Screen name="index" options={{ title: 'Home' }} /> <Stack.Screen name="about" options={{ title: 'About' }} /> </Stack> ); }
什么是 栈?
堆栈导航器是应用中在不同屏幕之间导航的基础。在 Android 上,堆栈路由会在当前屏幕上方进行动画显示。在 iOS 上,堆栈路由会从右侧进行动画显示。Expo Router 提供了一个 Stack 组件来创建导航堆栈,以添加新的路由。
🌐 A stack navigator is the foundation for navigating between different screens in an app. On Android, a stacked route animates on top of the current screen. On iOS, a stacked route animates from the right. Expo Router provides a Stack component to create a navigation stack to add new routes.
2
在屏幕之间导航
🌐 Navigate between screens
我们将使用 Expo Router 的 Link 组件从 /index 路由导航到 /about 路由。它是一个 React 组件,渲染一个带有指定 href 属性的 <Text>。
🌐 We'll use Expo Router's Link component to navigate from the /index route to the /about route. It is a React component that renders a <Text> with a given href prop.
- 在 index.tsx 中从
expo-router导入Link组件。 - 在
<Text>组件后添加一个Link组件,并使用/about路由传递href属性。 - 将
fontSize、textDecorationLine和color样式添加到Link组件。它接受与<Text>组件相同的属性。
import { Text, View, StyleSheet } from 'react-native'; import { Link } from 'expo-router'; export default function Index() { return ( <View style={styles.container}> <Text style={styles.text}>Home screen</Text> <Link href="/about" style={styles.button}> Go to About screen </Link> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', justifyContent: 'center', }, text: { color: '#fff', }, button: { fontSize: 20, textDecorationLine: 'underline', color: '#fff', }, });
让我们来看一下我们应用的变化。点击 Link 导航到 /about 路由:
🌐 Let's take a look at the changes in our app. Click on Link to navigate to the /about route:
3
添加未找到的路由
🌐 Add a not-found route
当某个路由不存在时,我们可以使用 +not-found 路由来显示备用屏幕。当我们希望在移动端导航到无效路由时显示自定义屏幕,而不是让应用崩溃或在网页上显示 404 错误时,这非常有用。Expo Router 使用一个特殊的 +not-found.tsx 文件来处理这种情况。
🌐 When a route doesn't exist, we can use a +not-found route to display a fallback screen. This is useful when we want to display a custom screen when navigating to an invalid route on mobile instead of crashing the app or display a 404 error on web. Expo Router uses a special +not-found.tsx file to handle this case.
- 在 app 目录中创建一个名为 +not-found.tsx 的新文件,以添加
NotFoundScreen组件。 - 从
Stack.Screen添加options属性以显示此路由的自定义屏幕标题。 - 添加一个
Link组件以导航到/路由,这是我们的后备路由。
import { View, StyleSheet } from 'react-native'; import { Link, Stack } from 'expo-router'; export default function NotFoundScreen() { return ( <> <Stack.Screen options={{ title: 'Oops! Not Found' }} /> <View style={styles.container}> <Link href="/" style={styles.button}> Go back to Home screen! </Link> </View> </> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', justifyContent: 'center', alignItems: 'center', }, button: { fontSize: 20, textDecorationLine: 'underline', color: '#fff', }, });
要测试此功能,请在网页浏览器中导航到 http:localhost:8081/123 URL,因为在那里更改 URL 路径很方便。应用应显示 NotFoundScreen 组件:
🌐 To test this, navigate to http:localhost:8081/123 URL in the web browser since it is easy to change the URL path there. The app should display the NotFoundScreen component:
4
添加底部标签导航
🌐 Add a bottom tab navigator
此时,我们的 app 目录的文件结构如下所示:
🌐 At this point, the file structure of our app directory looks like the following:
app_layout.tsxRoot layoutindex.tsxmatches route '/'about.tsxmatches route '/about'+not-found.tsxmatches route any 404 route我们将为应用添加一个底部标签导航,并重复使用现有的首页和关于页面来创建标签布局(这是许多社交媒体应用中常见的导航模式,例如 X 或 BlueSky)。我们还将在根布局中使用堆栈导航,以便 +not-found 路由显示在任何其他嵌套导航之上。
🌐 We'll add a bottom tab navigator to our app and reuse the existing Home and About screens to create a tab layout (a common navigation pattern in many social media apps like X or BlueSky). We'll also use the stack navigator in the Root layout so the +not-found route displays over any other nested navigators.
- 在 app 目录下,添加一个 (tabs) 子目录。这个特殊目录用于将路由组合在一起,并在底部标签栏中显示它们。
- 在目录中创建一个 (tabs)/_layout.tsx 文件。它将用于定义选项卡布局,这与根布局是分开的。
- 将现有的 index.tsx 和 about.tsx 文件移动到 (tabs) 目录中。app 目录的结构将如下所示:
app_layout.tsxRoot layout+not-found.tsxmatches route any 404 route(tabs)_layout.tsxTab layoutindex.tsxmatches route '/'about.tsxmatches route '/about'更新根布局文件以添加一个 (tabs) 路由:
🌐 Update the Root layout file to add a (tabs) route:
import { Stack } from 'expo-router'; export default function RootLayout() { return ( <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> </Stack> ); }
在 (tabs)/_layout.tsx 中,添加一个 Tabs 组件来定义底部选项卡布局:
🌐 Inside (tabs)/_layout.tsx, add a Tabs component to define the bottom tab layout:
import { Tabs } from 'expo-router'; export default function TabLayout() { return ( <Tabs> <Tabs.Screen name="index" options={{ title: 'Home' }} /> <Tabs.Screen name="about" options={{ title: 'About' }} /> </Tabs> ); }
现在让我们来看一下我们的应用,看看新的底部标签:
🌐 Let's take a look at our app now to see the new bottom tabs:
5
更新底部标签导航栏外观
🌐 Update bottom tab navigator appearance
目前,底部标签导航在所有平台上看起来都一样,但与我们应用的风格不匹配。例如,标签栏或标题栏没有显示自定义图标,底部标签的背景颜色也与应用的背景颜色不一致。
🌐 Right now, the bottom tab navigator looks the same on all platforms but doesn't match the style of our app. For example, the tab bar or header doesn't display a custom icon, and the bottom tab background color doesn't match the app's background color.
修改 (tabs)/_layout.tsx 文件以添加标签栏图标:
🌐 Modify the (tabs)/_layout.tsx file to add tab bar icons:
- 从
@expo/vector-icons导入Ionicons图标集 — 这是一个包含流行图标集的库。 - 将
tabBarIcon添加到index和about路由中。此函数以focused和color作为参数,并渲染图标组件。在图标集中,我们可以提供自定义的图标名称。 - 将
screenOptions.tabBarActiveTintColor添加到Tabs组件,并将其值设置为#ffd33d。这将更改标签栏图标和标签在激活时的颜色。
import { Tabs } from 'expo-router'; import Ionicons from '@expo/vector-icons/Ionicons'; export default function TabLayout() { return ( <Tabs screenOptions={{ tabBarActiveTintColor: '#ffd33d', }} > <Tabs.Screen name="index" options={{ title: 'Home', tabBarIcon: ({ color, focused }) => ( <Ionicons name={focused ? 'home-sharp' : 'home-outline'} color={color} size={24} /> ), }} /> <Tabs.Screen name="about" options={{ title: 'About', tabBarIcon: ({ color, focused }) => ( <Ionicons name={focused ? 'information-circle' : 'information-circle-outline'} color={color} size={24}/> ), }} /> </Tabs> ); }
让我们也使用 screenOptions 属性来更改标签栏和标题的背景颜色:
🌐 Let's also change the background color of the tab bar and header using screenOptions prop:
<Tabs screenOptions={{ tabBarActiveTintColor: '#ffd33d', headerStyle: { backgroundColor: '#25292e', }, headerShadowVisible: false, headerTintColor: '#fff', tabBarStyle: { backgroundColor: '#25292e', }, }} >
在上面的代码中:
🌐 In the above code:
- 页眉的背景使用
headerStyle属性设置为#25292e。我们还使用headerShadowVisible禁用了页眉的阴影。 headerTintColor将#fff应用于标题标签tabBarStyle.backgroundColor将#25292e应用于标签栏
我们的应用现在有了自定义的底部标签导航器:
🌐 Our app now has a custom bottom tabs navigator:
概括
🌐 Summary
Chapter 2: Add navigation
我们已经成功地在应用中添加了堆栈导航和标签导航。
在下一章中,我们将学习如何构建应用的第一个界面。