路由导航
react native 官网的主推方案就是一个单独的导航库 react-navigation ,使用 react-navigation 6.x ,官方文档:Getting started | React Navigation
安装
yarn add @react-navigation/native // 安装导航库
yarn add react-native-screens react-native-safe-area-context // 安装导航的依赖库
yarn add @react-navigation/native-stack // 安装栈路由
yarn add @react-navigation/bottom-tabs // 安装tab路由
yarn add @react-navigation/drawer // 安装抽屉路由
使用
路由配置文件:router/index.tsx
项目中所有需要进行路由跳转的页面都需要在这里进行配置,否则无法跳转成功。
import * as React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {TouchableOpacity} from 'react-native';
import {ChevronLeft} from 'react-native-feather';
const Stack = createNativeStackNavigator();
// 把需要跳转的页面先引入进来
import {Login} from '@/screens/Login/Login';
import {TabNavigator} from '@/components/TabNavigator';
import {Message} from '@/screens/My/component/Message';
function Route() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
screenOptions={({navigation}) => ({
headerShown: true, // 显示标题栏
headerTitleStyle: {fontSize: 16, fontWeight: 'bold', color: '#333333'}, // 修改标题文本样式
headerTitleAlign: 'center', // 标题居中
headerStyle: {backgroundColor: '#eee'}, // 修改标题栏背景颜色
// 修改左侧返回按钮图标样式
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.goBack()}>
<ChevronLeft width={24} height={24} color="#9C9A9D" />
</TouchableOpacity>
),
// 修改右侧按钮图标样式
headerRight: () => (),
})}>
{/* component 是引入的组件名,name 是进行路由跳转时候的name,跳转的时候用的是TabsLayout而不是TabNavigator */}
{/* 放置带tab的页面 */}
<Stack.Screen
name="TabsLayout"
component={TabNavigator}
options={{headerShown: false}}
/>
{/* 全屏页面 隐藏标题栏 headerShown: false */}
<Stack.Screen
name="Login"
component={Login}
options={{headerShown: false}}
/>
{/* 全屏页面 带标题栏 设置标题 title: '消息通知' */}
<Stack.Screen
name="Message"
component={Message}
options={{title: '消息通知'}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default Route;
其他页面进行路由跳转
1. 在 ts 中使用,示例:
上面在router/index.tsx 中,Login 已经配置了路由,这里会自带 navigation ,可以进行路由跳转,如果需要在此文件的其他方法使用,需要把 navigation 传过去
const FormChecked = ({navigation}: any) => {
const submit = () => {
request.post(url, data).then((res) => {
// 这里登录成功,自动跳转到首页
navigation.navigate('TabsLayout')
// 需要传参数的写法,接收在 route.params 里接收
navigation.navigate('TabsLayout', {id: res.data.id})
})
}
return(
<View></View>
)
}
export const Login = ({navigation}:any) => {
// 在这里也可以直接进行跳转
navigation.navigate('TabsLayout')
return (
<View>
{/* FormChecked 组件中要用到,需要传navigation过去 */}
<FormChecked navigation={navigation} />
</View>
);
}
2. 在 html 中使用,示例:
export const Login = ({navigation}:any) => {
return (
<View>
<View>
<Button
title="Go to Login"
onPress={() => navigation.navigate('TabsLayout')}
/>
</View>
</View>
);
}
带 tab 的页面:components/TabNavigator.tsx
/**
* 放置带tab的页面
*/
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Cloud, User } from "react-native-feather";
const Tab = createBottomTabNavigator();
import {Home} from "@/screens/Home/Home"
import {Settings} from "@/screens/Settings/Settings"
export function TabNavigator() {
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={{
tabBarActiveTintColor: '#2089DC', // 底部导航栏 选中时的颜色
}}
>
<Tab.Screen
name="Home"
component={Home}
options={{
title: "首页",
headerShown: false, // 隐藏标题栏
tabBarLabel: '首页',
tabBarIcon: ({ color, size }) => (
<Cloud stroke={color} width={size} height={size} />
),
}}
/>
<Tab.Screen
name="Settings"
component={Settings}
options={{
title: '我的',
headerShown: false, // 隐藏标题栏
tabBarLabel: '我的',
tabBarIcon: ({ color, size }) => (
<User stroke={color} width={size} height={size} />
),
}}
/>
</Tab.Navigator>
);
}
注意
1. 这里必须要把 NavigationContainer 作为根组件,否则不生效
// 错误的写法, 这里路由就没有生效
<View>
<Text>测试项目11</Text>
<NavigationContainer>
<Navigator initialRouteName="Home">
<Screen name="Home" component={Home} />
<Screen name="About" component={About} />
</Navigator>
</NavigationContainer>
</View>
// 正确的写法
<NavigationContainer>
<Text>测试项目11</Text>
<Navigator initialRouteName="Home">
<Screen name="Home" component={Home} />
<Screen name="About" component={About} />
</Navigator>
</NavigationContainer>
2. Screen 组件用来定义路由:路由配置、取名、渲染
3. 这里的 initialRouteName 是默认显示的页面,可以理解为首页
重置导航堆栈
退出登录的时候重置导航堆栈,解决React Navigation对屏幕的缓存会保留上一个屏幕的状态和参数,导致重新登录会进入退出前的最后一个画面的问题。
navigation.reset({
index: 0,
routes: [{ name: 'Login' }],
})
Navigation 方法总结
常用方法
导航到指定的路由(屏幕)
navigate(routeName, params)
routeName
: 要导航到的目标路由名称。params
(可选): 要传递给目标屏幕的参数。
push(routeName, params)
- 类似于
navigate()
。 - 与
navigate()
不同的是,push()
可以多次将相同的屏幕推入导航堆栈中。
返回上一个屏幕
goBack()
- 可以将它与
headerLeft
或自定义按钮一起使用。
弹出当前屏幕,返回上一个屏幕
pop()
- 与
goBack()
类似,但是pop()
可以处理更复杂的导航场景,如从堆栈中移除多个屏幕。
用指定的路由替换当前屏幕
replace(routeName, params)
- 替换当前屏幕时,不会在导航堆栈中创建新的屏幕。
重置导航堆栈为指定的状态
reset(state)
- 可以使用它来清除导航历史并导航到一个全新的堆栈。
次常用方法
更新当前屏幕的参数
setParams(params)
params
: 要更新的参数对象。
检查当前屏幕是否具有焦点
isFocused()
- 返回一个布尔值。
在导航生命周期事件发生时注册一个监听器
addListener(type, callback)
type
: 生命周期事件类型。例如:focus
,blur
,beforeRemove
等等。callback
: 将在事件发生时调用的回调函数。
获取当前屏幕的父导航器的导航对象
dangerouslyGetParent()
- 这个方法通常只在嵌套导航中使用。
不常用方法
发送一个动作到导航器中的所有屏幕
dispatch(action)
- 这个方法通常只在需要处理整个导航器状态的高级场景中使用。
检查当前屏幕是否可以返回到前一个屏幕
canGoBack()
- 返回一个布尔值。
发出一个事件到屏幕中的所有监听器
emit(eventName, data)
- 你可以通过添加事件监听器来接收这些事件。