Skip to content

栈导航(Stack Navigator)

第五部分:路由导航(页面跳转)

栈导航(Stack Navigator)是 React Navigation 中最基本的导航器类型,用于实现页面之间的层级跳转,类似于 Web 应用中的浏览器历史记录。本文将详细介绍 Stack Navigator 的使用方法。

1. 基本使用

创建栈导航器

首先,需要创建一个栈导航器并定义屏幕:

jsx
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
import ProfileScreen from './screens/ProfileScreen';

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

导航方法

在屏幕组件中,可以使用 navigation prop 提供的方法进行导航:

1. 跳转到新屏幕

jsx
// HomeScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>首页</Text>
      <Button
        title="跳转到详情页"
        onPress={() => navigation.navigate('Details')}
      />
      <Button
        title="跳转到个人资料页"
        onPress={() => navigation.navigate('Profile')}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
});

2. 返回上一页

jsx
// DetailsScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function DetailsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>详情页</Text>
      <Button
        title="返回首页"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="返回上一页"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
});

3. 重置导航栈

jsx
// ProfileScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function ProfileScreen({ navigation }) {
  const handleReset = () => {
    navigation.reset({
      index: 0,
      routes: [{ name: 'Home' }],
    });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>个人资料页</Text>
      <Button
        title="返回首页"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="重置导航栈"
        onPress={handleReset}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
});

2. 导航选项配置

基本选项

可以为每个屏幕配置导航选项:

jsx
<Stack.Navigator>
  <Stack.Screen 
    name="Home" 
    component={HomeScreen}
    options={{
      title: '首页',
      headerStyle: {
        backgroundColor: '#4CAF50',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    }}
  />
  <Stack.Screen 
    name="Details" 
    component={DetailsScreen}
    options={{
      title: '详情页',
      headerBackTitle: '返回',
    }}
  />
</Stack.Navigator>

全局选项

可以为整个导航器设置全局选项:

jsx
<Stack.Navigator
  screenOptions={{
    headerStyle: {
      backgroundColor: '#4CAF50',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
    headerBackTitle: '返回',
  }}
>
  <Stack.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
  <Stack.Screen name="Details" component={DetailsScreen} options={{ title: '详情页' }} />
</Stack.Navigator>

动态选项

可以根据路由参数动态设置导航选项:

jsx
<Stack.Screen 
  name="Details" 
  component={DetailsScreen}
  options={({ route }) => ({
    title: route.params?.title || '详情页',
  })}
/>

3. 参数传递

传递参数

在导航时可以传递参数:

jsx
// HomeScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>首页</Text>
      <Button
        title="跳转到详情页(带参数)"
        onPress={() => navigation.navigate('Details', {
          id: 1,
          title: '产品详情',
          price: 99.99,
        })}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
});

接收参数

在目标屏幕中接收参数:

jsx
// DetailsScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function DetailsScreen({ navigation, route }) {
  const { id, title, price } = route.params || {};

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{title || '详情页'}</Text>
      <Text style={styles.info}>ID: {id}</Text>
      <Text style={styles.info}>价格: ¥{price}</Text>
      <Button
        title="返回首页"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
  info: {
    fontSize: 16,
  },
});

更新参数

可以使用 setParams 方法更新当前屏幕的参数:

jsx
// DetailsScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function DetailsScreen({ navigation, route }) {
  const { id, title, price } = route.params || {};

  const updateTitle = () => {
    navigation.setParams({ title: '更新后的标题' });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{title || '详情页'}</Text>
      <Text style={styles.info}>ID: {id}</Text>
      <Text style={styles.info}>价格: ¥{price}</Text>
      <Button
        title="更新标题"
        onPress={updateTitle}
      />
      <Button
        title="返回首页"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
  info: {
    fontSize: 16,
  },
});

4. 高级用法

自定义导航栏

可以使用 header 选项自定义导航栏:

jsx
import React from 'react';
import { View, Text, Button, StyleSheet, TouchableOpacity } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function CustomHeader({ navigation, route }) {
  return (
    <View style={styles.header}>
      <TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
        <Text style={styles.backText}>←</Text>
      </TouchableOpacity>
      <Text style={styles.headerTitle}>{route.params?.title || '自定义标题'}</Text>
      <TouchableOpacity style={styles.rightButton}>
        <Text style={styles.rightText}>菜单</Text>
      </TouchableOpacity>
    </View>
  );
}

export default function CustomHeaderExample() {
  return (
    <Stack.Navigator>
      <Stack.Screen 
        name="Home" 
        component={HomeScreen}
        options={{ title: '首页' }}
      />
      <Stack.Screen 
        name="Details" 
        component={DetailsScreen}
        options={{
          header: (props) => <CustomHeader {...props} />,
        }}
      />
    </Stack.Navigator>
  );
}

const styles = StyleSheet.create({
  header: {
    height: 60,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    backgroundColor: '#4CAF50',
    paddingHorizontal: 16,
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#fff',
  },
  backButton: {
    padding: 8,
  },
  backText: {
    fontSize: 24,
    color: '#fff',
  },
  rightButton: {
    padding: 8,
  },
  rightText: {
    fontSize: 16,
    color: '#fff',
  },
});

隐藏导航栏

可以使用 headerShown 选项隐藏导航栏:

jsx
<Stack.Screen 
  name="Home" 
  component={HomeScreen}
  options={{ headerShown: false }}
/>

透明导航栏

可以创建透明导航栏:

jsx
<Stack.Screen 
  name="Home" 
  component={HomeScreen}
  options={{
    headerTransparent: true,
    headerTintColor: '#fff',
    headerTitle: '',
  }}
/>

动画配置

可以配置导航动画:

jsx
<Stack.Navigator
  screenOptions={{
    headerStyle: {
      backgroundColor: '#4CAF50',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
    cardStyleInterpolator: ({ current, layouts }) => {
      return {
        cardStyle: {
          transform: [
            {
              translateX: current.progress.interpolate({
                inputRange: [0, 1],
                outputRange: [layouts.screen.width, 0],
              }),
            },
          ],
        },
      };
    },
  }}
>
  {/* 屏幕配置 */}
</Stack.Navigator>

5. 常见问题与解决方案

问题 1:导航栏标题不显示

问题:导航栏标题不显示或显示不正确。

解决方案

  • 确保为屏幕设置了 title 选项
  • 检查是否使用了 headerTitle 选项覆盖了默认标题
  • 对于动态标题,确保正确使用了 route.params

问题 2:参数传递失败

问题:无法在屏幕之间传递参数。

解决方案

  • 确保使用正确的导航方法:navigation.navigate('ScreenName', { params })
  • 确保在目标屏幕中正确获取参数:const { route } = props; const { params } = route;
  • 检查参数是否为可序列化的值(避免传递函数或循环引用)

问题 3:导航栈管理

问题:导航栈管理混乱,出现重复屏幕或无法正确返回。

解决方案

  • 使用 navigation.reset() 重置导航栈
  • 使用 navigation.replace() 替换当前屏幕
  • 使用 navigation.navigate() 时,如果目标屏幕已在栈中,会返回该屏幕而不是创建新实例

问题 4:自定义导航栏样式

问题:无法自定义导航栏样式。

解决方案

  • 使用 headerStyleheaderTintColorheaderTitleStyle 等选项
  • 对于复杂的自定义,使用 header 选项提供自定义组件
  • 注意平台差异,某些样式在 iOS 和 Android 上可能表现不同

6. 最佳实践

1. 组织导航结构

将导航相关代码组织到单独的文件中:

jsx
// navigation/StackNavigator.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from '../screens/HomeScreen';
import DetailsScreen from '../screens/DetailsScreen';
import ProfileScreen from '../screens/ProfileScreen';

const Stack = createStackNavigator();

export default function AppStackNavigator() {
  return (
    <Stack.Navigator
      screenOptions={{
        headerStyle: {
          backgroundColor: '#4CAF50',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}
    >
      <Stack.Screen name="Home" component={HomeScreen} options={{ title: '首页' }} />
      <Stack.Screen name="Details" component={DetailsScreen} options={{ title: '详情页' }} />
      <Stack.Screen name="Profile" component={ProfileScreen} options={{ title: '个人资料' }} />
    </Stack.Navigator>
  );
}

2. 使用类型定义

为导航参数添加类型定义:

typescript
// navigation/types.ts
export type RootStackParamList = {
  Home: undefined;
  Details: {
    id: number;
    title: string;
    price?: number;
  };
  Profile: undefined;
};

// 使用类型
import { NativeStackScreenProps } from '@react-navigation/native-stack';

export default function HomeScreen({
  navigation,
}: NativeStackScreenProps<RootStackParamList, 'Home'>) {
  return (
    <View>
      <Button
        title="跳转到详情页"
        onPress={() => navigation.navigate('Details', { id: 1, title: '产品详情' })}
      />
    </View>
  );
}

3. 合理使用导航方法

  • navigation.navigate():跳转到新屏幕,会添加到导航栈
  • navigation.goBack():返回上一页
  • navigation.popToTop():返回导航栈的第一个屏幕
  • navigation.replace():替换当前屏幕,不会添加到导航栈
  • navigation.reset():重置整个导航栈

4. 处理深链接

配置深链接以支持从外部打开应用的特定页面:

jsx
// App.js
import React from 'react';
import { NavigationContainer, useLinking } from '@react-navigation/native';
import AppStackNavigator from './navigation/StackNavigator';

function App() {
  const { getInitialState } = useLinking({
    prefixes: ['myapp://', 'https://myapp.com'],
    config: {
      screens: {
        Home: '',
        Details: 'details/:id',
        Profile: 'profile',
      },
    },
  });

  const [isReady, setIsReady] = React.useState(false);
  const [initialState, setInitialState] = React.useState(null);

  React.useEffect(() => {
    const prepare = async () => {
      try {
        const state = await getInitialState();
        setInitialState(state);
      } catch (e) {
        console.error(e);
      } finally {
        setIsReady(true);
      }
    };

    prepare();
  }, [getInitialState]);

  if (!isReady) {
    return null;
  }

  return (
    <NavigationContainer initialState={initialState}>
      <AppStackNavigator />
    </NavigationContainer>
  );
}

export default App;

7. 总结

栈导航(Stack Navigator)是 React Navigation 中最常用的导航器类型,用于实现页面之间的层级跳转。通过本文的学习,你应该掌握了以下内容:

  1. Stack Navigator 的基本使用方法
  2. 导航方法的使用(navigate、goBack、reset 等)
  3. 导航选项的配置
  4. 参数传递和接收
  5. 高级用法(自定义导航栏、隐藏导航栏、动画配置)
  6. 常见问题的解决方案
  7. 最佳实践

在实际开发中,合理使用 Stack Navigator,可以创建出流畅、直观的页面导航体验,使应用更加专业和易用。

© 2026 编程马·菜鸟教程 版权所有