React Navigation:栈、标签与抽屉导航
React Navigation 完全指南:栈、标签与抽屉导航
React Navigation 是 React Native 生态中最受欢迎的导航解决方案。它提供了一套完整的导航模式,包括栈导航、标签导航和抽屉导航,能够轻松构建结构清晰、用户体验良好的移动应用。本教程将从零开始,带你掌握这三种核心导航器的用法及其组合技巧。
前置准备
在开始之前,确保你的项目已经初始化好 React Native 环境。如果还没有,可以使用 npx react-native init 创建。接着安装核心库和依赖:
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
对于 iOS,还需要执行 cd ios && pod install。之后根据要使用的导航器类型,分别安装对应的包:
npm install @react-navigation/native-stack # 栈导航
npm install @react-navigation/bottom-tabs # 底部标签导航
npm install @react-navigation/drawer # 抽屉导航
导航容器与基础结构
所有导航器必须包裹在 NavigationContainer 内,它负责管理导航树和应用状态。
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<NavigationContainer>
{/* 在这里放置你的导航器 */}
</NavigationContainer>
);
}
下面我们逐一拆解三种导航器。
栈导航器(Native Stack)
栈导航器使用“屏幕堆栈”模型,新屏幕推入栈顶,返回时弹出。createNativeStackNavigator 利用原生动画和手势,性能优于 JS 实现的 Stack Navigator。
创建基础栈
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function HomeScreen({ navigation }) {
return (
<View>
<Button
title="前往详情"
onPress={() => navigation.navigate('Details', { itemId: 42 })}
/>
</View>
);
}
function StackNavigator() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
initialRouteName指定默认显示的屏幕。- 通过
navigation.navigate('RouteName', params)携带参数跳转。 - 目标屏幕可通过
route.params获取参数。
自定义栈标题栏
Stack.Navigator 支持全局样式,Stack.Screen 可针对单个屏幕配置。
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' },
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: '首页' }}
/>
</Stack.Navigator>
常用的 screenOptions 属性包括 headerShown: false 可以隐藏标题栏,这在构建自定义导航栏时非常有用。
编程式导航与回退
navigation.goBack()返回上一页。navigation.popToTop()回到栈底。navigation.push('Route')即使该路由已在栈中,也会生成新实例。
标签导航器(Bottom Tabs)
底部标签导航是最常见的移动导航模式,适用于主功能模块之间的切换。React Navigation 提供 createBottomTabNavigator。
创建底部标签栏
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
function TabNavigator() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'Profile') {
iconName = focused ? 'person' : 'person-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
- 使用
tabBarIcon渲染图标,通常配合@expo/vector-icons或react-native-vector-icons。 tabBarActiveTintColor和tabBarInactiveTintColor控制激活与非激活颜色。- 如果某个标签不需要导航栏头,可设置
options={{ headerShown: false }}。
自定义选项卡外观
通过 tabBarStyle 可以调整标签栏背景色、高度、边框等:
<Tab.Navigator
screenOptions={{
tabBarStyle: { backgroundColor: '#6200ee', borderTopWidth: 0 },
tabBarLabelStyle: { fontSize: 12 },
}}
>
抽屉导航器(Drawer)
抽屉导航从屏幕侧边滑出菜单,适合功能多、层级深的应用。createDrawerNavigator 默认附带手势和遮罩。
创建抽屉导航
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
function DrawerNavigator() {
return (
<Drawer.Navigator
screenOptions={{
drawerActiveTintColor: '#e91e63',
headerTintColor: '#fff',
headerStyle: { backgroundColor: '#e91e63' },
}}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
);
}
- 自定义抽屉内容可使用
drawerContent属性,传入自定义组件。 drawerType可以设置为'front'、'back'或'slide'控制动画。edgeWidth和swipeEnabled控制左滑手势的触发范围和开关。
自定义抽屉菜单
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}
>
{/* ... */}
</Drawer.Navigator>
在 CustomDrawerContent 中,你可以使用 DrawerContentScrollView 和 DrawerItemList 构建定制化的菜单项。
嵌套导航器
实际项目中很少只使用一种导航器,通常需要嵌套。例如:一个包含底部标签的应用,每个标签页内部有自己的栈导航。
典型结构示例
// 每个标签页的内部栈导航
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeMain" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
// 主标签导航器
function AppTabs() {
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="HomeTab" component={HomeStack} />
<Tab.Screen name="ProfileTab" component={ProfileScreen} />
</Tab.Navigator>
);
}
// 根导航器可以再包裹一个抽屉
function RootNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Main" component={AppTabs} />
<Drawer.Screen name="Settings" component={SettingsScreen} />
</Drawer.Navigator>
);
}
- 嵌套时注意标题栏的归属:通常在叶子导航器中显示标题,父级导航器设置
headerShown: false,避免双重标题。 - 可以跨导航器跳转,但需要明确目标路由的全路径,或使用
navigation.getParent()获取父导航器。
参数传递与类型安全(TypeScript)
使用 TypeScript 可以获得完整的参数校验和自动补全。
type RootStackParamList = {
Home: undefined;
Details: { itemId: number };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
此时 navigation.navigate('Details', { itemId: 123 }) 会强制你提供正确的参数。
常见问题与性能优化
- 内存管理:React Navigation 默认保持栈内所有屏幕挂载,对于列表详情场景,可以使用
useIsFocused钩子暂停非活跃屏幕的网络请求或动画。 - 延迟加载:使用
React.lazy配合Suspense实现屏幕代码分割,或利用component属性的动态 import 减少初始包大小。 - 手势冲突:当嵌套多个可滑动的导航器(如 Drawer 嵌套在 Tab 中),需合理配置
gestureEnabled和swipeEnabled以避免误触。
总结与下一步
- 栈导航:适合页面间的深度跳转,保留返回历史。
- 标签导航:适合同级主功能的快速切换,通常置于应用底部。
- 抽屉导航:适合侧边栏式全局菜单,承载低频但重要的入口。
掌握这三种导航器及其嵌套方式,你可以构建任意复杂度的 React Native 应用导航结构。建议查阅官方文档深入学习每个导航器的进阶配置,如透明模态、共享元素动画等。
现在尝试改造你的项目,为不同功能区域选择合适的导航模式,并组合它们来提升用户体验。