react-native之导航器

4,445 阅读6分钟

一、前言

公司需要做一款app。因为我本身是做前端的,所以技术栈选择了react-native

因为我之前有一些做小程序与Vue的经验,所以在接到这个任务时,我大概从下面几方面的问题去考虑该怎样去做这个app

  1. 路由管理

    小程序在app.json中,pages放置全部的路由,在tabBar中放置所有BottomTabBar的路由,并且使用wx.navigateTo跳转普通页面,使用wx.switchTab跳转tabBar页面

    那么react-native是怎么去处理普通页面的路由和tabBar页面的路由的呢?

    小程序的路由API除了跳转tabBar页面是不能带参数的,其他都是可以在路径后面带参数

    **那么react-native是怎么在跳转路由时携带参数呢 **

    Vue中有嵌套路由的概念

    react-native是否有类似的概念呢

  2. 状态管理

    Vue有Vuex可以实现全局的状态管理,react有redux,

    **在react-native中应该如何去处理呢 **

    react-native状态管理的数据持久化又应该怎么做呢

  3. 网路请求

    react-native是怎么实现网络请求的

    是否可以使用第三方库axios

  4. 生命周期,钩子函数

    小程序和Vue都有生命周期函数,用来做特定时期的特定动作

    那么react-native是否有生命周期函数呢

  5. 调用硬件功能

    react-native怎么去调用手机的摄像头

    react-native怎么去获取用户的相片

    react-native怎么去获取用户授权等

根据综上问题去学习react-native,这篇文章便是来总结react-native是怎么编写路由的

二、路由栈

我会使用react navigation 4.x的库,这是官网的网址https://reactnavigation.org/docs/zh-Hans/4.x/getting-started.html

怎么安装,官网写的非常详细,这里不赘述

RN中的路由是一个栈的概念,如下

屏幕快照 2020-02-08 下午2.13.34

当我们从首页点击到设备页,再点击到设备详情页时,就是不断往栈中加入路由,返回时,也是先把设备详情页从栈中拿掉,再拿设备页,直到剩下首页

三、创建路由栈

createStackNavigator可以创建路由栈

npm install react-navigation-stack @react-native-community/masked-view安装依赖

import {createStackNavigator} from "react-navigation-stack"
const AppNavigator = createStackNavigator({
  //路由的名字:路由的页面
  Home:HomePage,// HomePage 需要自己编写并导入
  Device:DevicePage,
  DeviceDetail:DeviceDetailPage,
  // 需要注意,上面引入的页面的顺序不会影响路由栈的显示
},{
  	// 初始化的路由页面是什么
  	initialRouteName:"Home"//初始化页面显示HomePage
})

四、路由的跳转

我们创建的AppNavigator会给HomePage,DevicePage,DeviceDetailPage 页面组件传递 navigation这个prop,我们可以用navigation来实现页面的跳转

import React,{Component} from "react"
export default class HomePage extends Component{
  render(){
    <View>
    	<Text>首页</Text>
      <Button
      	title="跳转到设备页"
        onPress={()=>{
          this.props.navigation.navigate("Device")
        }}
      />
    </View>
  }
}

路由跳转的API

this.props.navigation.navigate("组件路由名字")
this.props.navigation.push('组件路由名字')
this.props.navigation.goBack('组件路由名字')
//goBack()括号内可不写,如果组件路由名字和上个页面的路由名字不一致,则不会跳转,
this.props.navigation.popToTop('组件路由名字')
//popToTop()括号内可不写,如果组件路由名字和最上层页面的路由名字不一致,则不会跳转,

navigate: 会判断栈中有没有这个组件,如果有则回到那个页面,如果没有则创建一个新的组件进行压栈展示

push:创建一个新的组件 ,进行压栈展示

goBack:返回上一个页面

popToTop:回到首页组件

页面之间传递参数

this.props.navigation.navigate方法可以传递参数到下一个页面,如下面代码所示

<View>
	<Text>首页</Text>
  <Button
  	title="跳转到详情页"
    onPress={()=>this.props.navigation.navigate('Details',{
      newsId:"100",
      newsName:"新闻1",
      newsTag:"重要"
    })}
   ></Button>
</View>

页面接收参数

<Text>参数1:{this.props.navigation.getParam("newsId")}</Text>
<Text>参数2:{this.props.navigation.getParam("newsName")}</Text>
<Text>参数3:{this.props.navigation.getParam("newsTag")}</Text>
<Text>所有参数:{this.props.navigation.state.params}</Text>

五、创建BottomTabBar

image-20200208150819462

npm install react-navigation-tabs安装依赖

import {createBottomTabNavigator,BottomTabBar} from "react-navigation-tabs"
import Icons from "react-native-vector-icons/Feather"
const AppBottomTabBar = createBottomTabNavigator({
  Home:{
    screen:HomePage,
    navigationOptions:{
      title:"首页",//设定标题
      //显示的图标
      tabIcon:({tintColor,focused})=>(
    		<Icons 
            name={'home'}
            size={26}
            style={{color:tintColor}}
         />
    	)
    }
  },
  Device:DevicePage,
  Message:MessagePage,
  Mine:MinePage
},{
  // 底部标签栏要展示的组件
  tabBarComponent:props=>(
    // activeTintColor为选中时的颜色
  	 <BottomTabBar {...props} activeTintColor="#34b5ff"/>
  )
})

react-native有配套的icon库https://github.com/oblador/react-native-vector-icons,

npm install --save react-native-vector-icons安装依赖

react-native link react-native-vector-icons 让图标能在ios和android上显示

六、tabBar路由和普通页面路由组合起来

有个需求如下:

image-20200208153621816

在欢迎页面显示一秒后跳转到登陆页面,登陆成功则显示tabBar页面,tabBar页面可以跳转到其他页面

因为路由栈是连续的,我不希望在登陆成功后,tabBar页面还能返回到登陆页面

createSwitchNavigator

SwitchNavigator 可以帮助我们

SwitchNavigator 的用途是一次只显示一个页面。 默认情况下,它不处理返回操作,并在你切换时将路由重置为默认状态。 这是我们希望从身份验证流程获得的确切行为。

import {createSwitchNavigator,createAppContainer} from "react-navigation"
import {createStackNavigator} from "react-navigation-stack"
const InitNavigator = createStackNavigator({
    Welcome:WelcomePage,
    Login:LoginPage,
})
const MainNavigator = createStackNavigator({
    Home:{// Home即是tabBar页面
        screen:BottomTabPage,
        navigationOptions:{
            headerShown:false
        }
    },
    DeviceDetail:DeviceDetailPage,
})
export const RootNavigator = createAppContainer(createSwitchNavigator({
    Init:InitNavigator,
    Main:MainNavigator
}))

tabBar页面是创建BottomTabBar,并返回BottomTabBar页面的组件

// BottomTabPage
import React,{Component} from "react"
import Icons from "react-native-vector-icons/Feather"
import {createBottomTabNavigator,BottomTabBar} from "react-navigation-tabs"
import {createAppContainer} from "react-navigation"
import {
    StyleSheet,
    Image,   
} from "react-native"
import  HomePage from "../page/HomePage"
import DevicePage from "../page/DevicePage"
import MinePage from "../page/MinePage"
import MessagePage from "../page/MessagePage"

const Tabs = {
    Home:{
        screen:HomePage,
        navigationOptions:{
            title:"首页",
            tabBarIcon:({tintColor,focused})=>(
                <Icons 
                    name={'home'}
                    size={26}
                    style={{color:tintColor}}
                />
            )
        }
    },
    Device...,
    Message...,
    Mine...,
}
export default class MainTabNavigator extends Component{
    _Navigator(){
        const {Home,Device,Message,Mine} = Tabs;
        const tabs={Home,Device,Message,Mine}
        if(!this.navigator){
            this.navigator=createAppContainer(createBottomTabNavigator(
                tabs,{
                    tabBarComponent:props=>
                    <BottomTabBar {...props} activeTintColor="#34b5ff"/>
                }
            ))
        }
        return this.navigator
    }
    render(){
        const TabNavigator = this._Navigator()
        return <TabNavigator/>;
    }
}

const styles = StyleSheet.create({
    BottomTabBarIconImage:{
        width:30,
        height:30
    }
})

总结现在的路由结构

switchNavigator (/Users/huzhiwu/Desktop/react-native-learn/switchNavigator (5).png)

当我在LoginPage登陆成功时,可以这样子跳转到home页面

this.props.navigation.navigate("main")//因为Home排序第一,所以跳转到main页面时会显示Home页面

Home页面如下

image-20200208161809341

当我点击我的tab时会跳转到MinePage,当想要从MinePage页面跳转到其他页面(个人信息页面等)时。却行不通了

switchNavigator (/Users/huzhiwu/Desktop/react-native-learn/switchNavigator (6).png)

为了解决这个问题,我们就必须要在Home页面时,就保存navigation然后,在MinePage去使用

//NavigatiorUtil
export default class NavigatorUril{
    static goPage(params,page){
        // 在BottomTabBar页面接受navigation
        const navigation = NavigationUtil.navigation
        if(!navigation){
            console.log("NavigationUtil.navigation can not be null")
            return;
        }
        navigation.navigate(
            page,
            {
                ...params
            }
        )
    }
}
// Home页面
import NavigationUtil from "../navigator/NavigationUtil"
export default class BottomTabPage extends Component{
    render(){
        NavigationUtil.navigation = this.props.navigation
        return(
            <View style={styles.wrapper}>
                <MainTabNavigator/>
            </View>
            
        )
    }
}
// MinePage
import NavigationUtil from "../navigator/NavigationUtil"
export default class MinePage extends Component {
    render(){
        return (
            <View style={styles.wrapper}>
                <Text style={styles.item}>我的</Text>
                <TouchableHighlight
                    style={styles.button}
                    onPress={()=>{
                        NavigationUtil.goPage({},"DeviceGroupManager")
                    }}
                >
                    <Text style={styles.btnText}>跳转个人信息</Text>
                </TouchableHighlight>
            </View>
        )
    }
}

七、创建TopBarNavigatior

createMaterialTopTabNavigator

import {createMaterialTopNavigator} from "react-navigation-tabs"
import {createAppContainer} from "react-navigation"
export default class HomePage extends Component {
    _topTabBar(){
        if(!this.topTabBar){
            this.topTabBar = createAppContainer(createMaterialTopTabNavigator({
                tab1:{
                    screen:HomeDevicePage,
                    navigationOptions:{
                        title:"家庭"
                    }
                },
                tab2:{
                    screen:SchoolDevicePage,
                    navigationOptions:{
                        title:"学校"
                    }
                }
            },{
                tabBarOptions: {
                    tabStyle: styles.tabStyle,//选项卡等样式对象,
                    upperCaseLabel: false,//是否使标签大写,默认为true
                    scrollEnabled: true,//是否支持 选项卡滚动,默认false
                    style: {// 选项卡栏等样式对象
                        backgroundColor: "#fff",//TabBar 的背景颜色
                        height: 30,
                    },
                    indicatorStyle: styles.indicatorStyle,//标签指示器的样式
                    labelStyle: styles.labelStyle,//文字的样式
                },
                lazy: true
            }))
        }
        return this.topTabBar
    }
    render(){
        const  TopTabBar = this._topTabBar() 
        return (
            <View style={{flex:1,marginTop:30}}>
                <TopTabBar/>
            </View>
        )
    }
}

结语

如果文章中有错漏处,请看官们指正 如果觉得文章不错的话,请点个赞吧。

作者:胡志武

时间:2020/02/08