跳至主要内容
版本: 6.x

屏幕间跳转

在上一节"Hello React Navigation"中,我们定义了一个包含两个路由(HomeDetails)的堆栈导航器,但我们没有学习如何让用户从 Home 导航到 Details(虽然我们确实学习了如何在代码中更改初始路由,但强迫用户克隆我们的仓库并在我们的代码中更改路由以查看另一个屏幕,可以说是最糟糕的用户体验之一)。

如果这是一个网页浏览器,我们可以这样写

<a href="details.html">Go to Details</a>

另一种写法是

<a
onClick={() => {
window.location.href = 'details.html';
}}
>
Go to Details
</a>

我们将做类似于后者的事情,但不是使用 window.location 全局变量,我们将使用传递给屏幕组件的 navigation 属性。

import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}

// ... other code from the previous section

让我们分解一下

  • navigation - navigation 属性被传递到原生堆栈导航器中的每个**屏幕组件**(定义)。(稍后在"深入了解 navigation 属性"中将详细介绍)。
  • navigate('Details') - 我们使用要将用户移动到的路由的名称调用navigate 函数(在navigation 属性上 - 命名很困难!)。
注意

如果我们使用在导航器中未定义的路由名称调用navigation.navigate,它将在开发版本中打印错误,而在生产版本中不会发生任何事情。换句话说,我们只能导航到已在导航器中定义的路由 - 我们不能导航到任意组件。

因此,我们现在有一个包含两个路由的堆栈:1) Home 路由 2) Details 路由。如果我们从Details 屏幕再次导航到Details 路由会发生什么?

function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}

如果您运行此代码,您会注意到当您点击“再次转到详细信息...”时,它不会执行任何操作!这是因为我们已经在 Details 路由上了。navigate 函数大致意味着“转到此屏幕”,如果您已经在该屏幕上,那么它不执行任何操作是有道理的。

假设我们实际上想要添加另一个详细信息屏幕。这在您将一些唯一数据传递到每个路由的情况下非常常见(稍后在讨论params时会详细介绍!)。为此,我们可以将navigate 更改为push。这使我们能够表达添加另一个路由的意图,而不管现有的导航历史记录如何。

<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>

每次调用push都会在导航栈中添加一条新的路由。当您调用navigate时,它会首先尝试查找具有该名称的现有路由,并且只有在栈中还没有该路由时才会推送新的路由。

返回

由原生栈导航器提供的标题将在可以从活动屏幕返回时自动包含一个返回按钮(如果导航栈中只有一个屏幕,则没有可以返回的内容,因此没有返回按钮)。

有时您可能希望能够以编程方式触发此行为,为此您可以使用navigation.goBack();

function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
注意

在 Android 上,React Navigation 会挂钩到硬件返回按钮,并在用户按下它时为您触发goBack()函数,因此它的行为符合用户的预期。

另一个常见的要求是能够返回多个屏幕——例如,如果您在栈中深入多个屏幕,并且想要关闭所有屏幕以返回到第一个屏幕。在这种情况下,我们知道我们想要返回到Home,因此我们可以使用navigate('Home')(不是push!试试看,看看区别)。另一种选择是navigation.popToTop(),它会返回到栈中的第一个屏幕。

function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
<Button
title="Go back to first screen in stack"
onPress={() => navigation.popToTop()}
/>
</View>
);
}

总结

  • navigation.navigate('RouteName')如果该路由不在栈中,则会将新的路由推送到原生栈导航器,否则它会跳转到该屏幕。
  • 我们可以根据需要多次调用navigation.push('RouteName'),它会继续推送路由。
  • 标题栏会自动显示返回按钮,但您可以通过调用navigation.goBack()以编程方式返回。在 Android 上,硬件返回按钮按预期工作。
  • 您可以使用navigation.navigate('RouteName')返回到栈中的现有屏幕,也可以使用navigation.popToTop()返回到栈中的第一个屏幕。
  • navigation道具可用于所有屏幕组件(在路由配置中定义为屏幕的组件,并由 React Navigation 作为路由渲染)。