RN导航路由配置(包含禁用左右滑动返回到上一个页面,以及无组件导航的案例)

tabbar底部导航栏

安装依赖包

需要安装四个依赖包(自己找适配自己RN的导航版本,我这里RN下面的依赖目前都是最新的,如下图所示)react-navigation/native 网站
yarn add @react-navigation/native
yarn add @react-navigation/bottom-tabs
yarn add react-native-screens react-native-safe-area-context

在这里插入图片描述

新建两个tabbar页面

这里我做的homeScreen.jsSettingsScreen.js

homeScreen.js

import {Text, View} from 'react-native';

export default function homeScreen() {
  return (
    <View>
      <Text>123</Text>
    </View>
  );
}

SettingsScreen.js

import {Text, View} from 'react-native';

export default function SettingsScreen() {
  return (
    <View>
      <Text>456</Text>
    </View>
  );
}

配置tabbar页面,这里新起个页面,例如我这里做个MyTabs.js

MyTabs.js

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './homeScreen'
import SettingsScreen from './SettingsScreen'
import { Image } from 'react-native';
const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} options={{tabBarIcon:({color,size})=>{
        return (  // 底部栏图标
          <Image style={{width:15,height:15}} source={require('./1212.png')}></Image>
        )
      }}}/>
      <Tab.Screen name="Settings" component={SettingsScreen} options={{tabBarIcon:({color,size})=>{
        return (
          <Image style={{width:15,height:15}} source={require('./1212.png')}></Image>
        )
      }}}/>
    </Tab.Navigator>
  );
}

export default MyTabs

App.js内容如下

import { NavigationContainer } from '@react-navigation/native';
import MyTabs from './src/MyTabs';
function App() {
  return (
    <NavigationContainer>
      <MyTabs />
    </NavigationContainer>
  );
}
export default App

项目结构如下:
在这里插入图片描述
效果图
在这里插入图片描述

非tabbar页面的导航

安装三个插件
yarn add @react-navigation/native 如果上面装过了这个就不用装了
yarn add @react-navigation/stack
yarn add react-native-gesture-handler

homeScreen.js

import {Button, Text, View} from 'react-native';

export default function homeScreen(params) {
  console.log(params);
  return (
    <View>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Text>123</Text>
      <Button title='点击跳转另一个页面' onPress={()=>{params.navigation.navigate('Setting',{name:'zhangsan'})}}></Button>
    </View>
  );
}

settingsScreen.js

import {Button, Text, View} from 'react-native';

export default function SettingsScreen(props) {
  return (
    <View>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Text>456</Text>
      <Button title='返回到上一级' onPress={()=>{props.navigation.goBack()}}></Button>
    </View>
  );
}

配置导航路由页面MyTab.js

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './homeScreen';
import SettingsScreen from './SettingsScreen';

const Stack = createStackNavigator();

function MyTabs() {
  return (
    <Stack.Navigator> // screenOptions={{ headerShown: false }} 这里还有个参数可以隐藏上面的导航条,我这里没有加,如果有需要隐藏就加上,如果需要这个返回键又需要在导航条加样式的话,建议自己做个组件
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Setting" component={SettingsScreen} />
    </Stack.Navigator>
  );
}

function App() {
  return (
    <NavigationContainer>
      <MyTabs />
    </NavigationContainer>
  );
}

export default App;

App.js

import MyTabs from './src/MyTabs';
function App() {
  return (
      <MyTabs />
  );
}
export default App

效果图
在这里插入图片描述
点击跳转后的效果图
在这里插入图片描述

跳转后的新页面可以通过props.route拿到路由参数

既有底部导航,也有页面导航

下载的依赖包就是上面两种所安装的所有的

示例代码

import {Text, StyleSheet, View, Button} from 'react-native';
import React, {Component} from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {NavigationContainer} from '@react-navigation/native';
const Tab = createBottomTabNavigator();

function FeedScreen(props) {
  // 跳转方法prop.navigation.navigate参数是路由名称也就是Stack.Screen name
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>HomeScreen</Text>
      <Button
        title={'跳到Profile页面'}
        onPress={() => props.navigation.navigate('Profile')}
      />
      <Button
        title={'跳到Settings页面'}
        onPress={() => props.navigation.navigate('Settings')}
      />
    </View>
  );
}

function MessagesScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>NewsScreen</Text>
    </View>
  );
}

function ProfileScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>ProfileScreen</Text>
    </View>
  );
}

function SettingsScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>SettingsScreen</Text>
    </View>
  );
}

function Home() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Messages" component={MessagesScreen} />
    </Tab.Navigator>
  );
}

const Stack = createStackNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen
            name="Home"
            component={Home}
            options={{headerShown: false}}
          />
          <Stack.Screen name="Profile" component={ProfileScreen} />
          <Stack.Screen name="Settings" component={SettingsScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});

在app.js引入

import MyTabs from './src/MyTabs';
function App() {
  return (
      <MyTabs />
  );
}
export default App

效果图
在这里插入图片描述

在这里插入图片描述
自定义底部导航栏样式(还是以上面代码为基准,给Home这个组件内的Tab.Navigator这个标签加个tabBar属性,这个指向的就是自定义标题栏)

import {Text, StyleSheet, View, Button, TouchableOpacity} from 'react-native';
import React, {Component} from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {NavigationContainer} from '@react-navigation/native';
const Tab = createBottomTabNavigator();

function FeedScreen(props) {
  // 跳转方法prop.navigation.navigate参数是路由名称也就是Stack.Screen name
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>HomeScreen</Text>
      <Button
        title={'跳到Profile页面'}
        onPress={() => props.navigation.navigate('Profile')}
      />
      <Button
        title={'跳到Settings页面'}
        onPress={() => props.navigation.navigate('Settings')}
      />
    </View>
  );
}

function MessagesScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>NewsScreen</Text>
    </View>
  );
}

function ProfileScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>ProfileScreen</Text>
    </View>
  );
}

function SettingsScreen(props) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>SettingsScreen</Text>
    </View>
  );
}

let asaq = [
  {
    name: 'Messages',
  },
  {
    name: 'Settings',
  },
];
function TabBar({navigation, state}) {
  console.log('props', navigation);
  console.log('state', state);
  // 下面这个就是自定义的tabbar样式,各位自行修改
  return (
    <View style={{height:100,flexDirection:'row',justifyContent:'space-around'}}>
      {asaq.map((item, index) => {
        return (
          <TouchableOpacity
            onPress={() => {
              navigation.navigate(item.name);
            }}>
            <Text>{item.name}</Text>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

function Home() {
  //tabbar属性是自定义底部导航栏的样式
  return (
    <Tab.Navigator tabBar={props => <TabBar {...props} />}>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Messages" component={MessagesScreen} />
    </Tab.Navigator>
  );
}

const Stack = createStackNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen
            name="Home"
            component={Home}
            options={{headerShown: false}}
          />
          <Stack.Screen name="Profile" component={ProfileScreen} />
          <Stack.Screen name="Settings" component={SettingsScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});

上面这个自定义的导航可以直接在自定义的导航上面加样式,也可以使用绝对定位定位到任意位置

在我们某一页面我们不希望用户可以返回到上一个页面,但是发现即使使用了navigation.replace(‘路由名称’)也阻止不了用户左右滑动返回到上一个界面,本人亲测下面这个方法非常好使,各位可以试试

import React, { useEffect } from 'react';
import { BackHandler } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const App = () => {
  useEffect(() => {
  // 使用BackHandler监听 Android 设备上的物理返回按钮(即硬件返回按钮)的按下事件。
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        // 在此处添加你的逻辑来阻止安卓上的返回事件
        return true; // 返回 true 表示已经处理了返回事件,不会继续传递
      }
    );

    return () => backHandler.remove();
  }, []);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{
            gestureEnabled: false, // 禁用IOS的左滑返回
          }}
        />
        {/* 其他屏幕 */}
      </Stack.Navigator>
    </NavigationContainer>
  );
};

const HomeScreen = () => {
  return (
    // 主屏幕内容
  );
};

export default App;

无组件导航的案例

由于上面的导航都过于依赖组件,例如导航要依赖于hooks函数,通过hooks进行导航,或者直接使用组件导航到某一页面携带的navigation进行导航,但是如果方法是在一个纯js文件里面呢??怎么导航???例如我封装了一个axios.js函数,在响应拦截器里面设置当后端返回登录过期就要跳转到登录页面,那这样该怎么实现呢???就以这个案例做一下下面的封装,这个封装的函数可以在纯js文件进行调用跳转,无需依赖于页面的导航

创建工具文件

  • 这个工具文件封装了一个导航,可以跳转指定页面,同时也封装了一个函数用于返回几层页面
import {createNavigationContainerRef} from '@react-navigation/native';
import {StackActions} from '@react-navigation/native';

export const navigationRef = createNavigationContainerRef();
/**
 * 跳转到某个页面
 * @param name  页面name
 * @param params  可选,参数携带
 */
export const to = (name, params = {}) => {
  if (navigationRef.isReady()) {
    // @ts-ignore
    navigationRef.navigate(name, params);
  }
};

/**
 * 返回
 * @param count  返回几层,不写返回一层
 */
export const back = (count = 1) => {
  if (navigationRef.isReady()) {
    navigationRef.dispatch(StackActions.pop(count));
  }
};

导航器文件内添加这个工具文件属性

如果根据上面的配置配置了导航器,就找到导航器,在这个导航器页面就两个操作

  1. 引入工具包,解构出navigationRef
  2. 将工具包的navigationRef添加到NavigationContainer组件的ref属性上

下面是示例代码

import React, {Component, useContext, useEffect, useState} from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {NavigationContainer} from '@react-navigation/native';
import LoginScreen from '../pages/user/signin';  // 登录页
import StaffIndex from '../pages/coach/staff/index'; // 数据页面
const {width, height} = Dimensions.get('window');
const Tab = createBottomTabNavigator();

// 1.引入工具包
import {navigationRef} from '../utils/index';

const Stack = createStackNavigator();

export default function Index() {
  // 阻止手势左右滑动返回
  useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        // 在此处添加你的逻辑来阻止安卓上的返回事件
        return true; // 返回 true 表示已经处理了返回事件,不会继续传递
      },
    );
    return () => backHandler.remove();
  }, []);
  
  return (
  	// 2.将工具包添加到 NavigationContainer 属性上面去
    <NavigationContainer ref={navigationRef}>
      <Stack.Navigator
        screenOptions={{headerShown: false, gestureEnabled: false}}>
        <Stack.Screen name="StaffIndex" component={StaffIndex} />
         ...
         	其他组件配置
         ...
        <Stack.Screen name="Privacy" component={Privacy} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({});

使用

这里使用我个人封装的axios文件,当后端返回的是登录过期,则跳转登录页面,这个页面也是两步操作

  1. 引入工具包,解构出to方法
  2. 登录过期,使用to方法执行跳转首页

下面是示例代码

import axios from 'axios';
import Toast from 'react-native-root-toast';
import AsyncStorage from '@react-native-async-storage/async-storage';

// 1.引入工具包,解构出to方法
import {to} from '../utils/index';

const instace = axios.create({
  baseURL: 'https://internal.takehr.cn', //接口地址
  timeout: 5000, //超时时间
});

//配置请求拦截器,在请求之前的数据处理,比如在请求头添加token,所有的请求都会经过拦截器
instace.interceptors.request.use(
  async config => {
    try {
      const token = await AsyncStorage.getItem('token');
      const venue = await AsyncStorage.getItem('venueSn');
      if (token) {
        // console.log('JSON.parse(token)',JSON.parse(token));
        config.headers.token = JSON.parse(token);
      }
      if (venue) {
        // console.log('JSON.parse(venue)', JSON.parse(venue));
        config.headers['venue-sn'] = JSON.parse(venue);
      }
      // console.log('config', config);
      return config;
    } catch (error) {
      return Promise.reject(error);
    }
  },
  err => {
    return Promise.reject(err);
  },
);

//配置响应拦截器
// 响应拦截器:在请求响应之后对数据处理,比如:登录失败、请求数据失败的处理
instace.interceptors.response.use(
  response => {
    if(response.data.code === '登录过期'){
    	// 2.登录过期,使用to方法执行跳转首页
		to('LoginScreen');
		return;
	}
	
    if (response.data.code != 1) {
      Toast.show(response.data.msg, {
        duration: 2000, // 显示时长
        position: Toast.positions.CENTER, // 将弹窗内容居中显示
      });
    }
    return response; //这里的response就是请求成功后的res , response.data即是请求成功后回调函数内的参数res.data
  },
  err => {
    console.log('err', err);
    Toast.show(err.message, {
      duration: 2000, // 显示时长
      position: Toast.positions.CENTER, // 将弹窗内容居中显示
    });
    return Promise.reject(err); //将错误消息挂到promise的失败函数上
  },
);

//封装请求的api
const callapi = (method = 'GET', url, data = {}, customHeaders = {}) => {
  if (method === 'GET') {
    return instace({
      method,
      url,
      params: data,
      ...customHeaders,
    });
  } else {
    return instace({
      method,
      url,
      params: {},
      data: data,
      ...customHeaders,
    });
  }
};
//封装GET,POST请求函数
export const getapi = (url, data, customHeaders) =>
  callapi('GET', url, data, customHeaders);
export const postapi = (url, data, customHeaders) =>
  callapi('POST', url, data, customHeaders);

参考教程

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧寂173

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值