react-navigation导航器
- 2019 年 10 月 5 日
- 筆記

https://reactnavigation.org/ ——源于React Native社区对基于Javascript的可扩展且使用简单的导航解决方案的需求 。
和h5用a标签来跳转不太一样的是,rn必须依赖导航器跳转。导航器也可以看成是一个普通的React组件,你可以通过导航器来定义你的APP中的导航结构。导航还可以渲染通用元素,例如可以配置的标题栏和选项卡栏。
react-natvigation自开源以来。在短短不到3个月的时间,github上星数已达4000+。它是Fb推荐使⽤库, 并且在React Native当前最新版本0.44中将Navigator删除。react-navigation据称有原生般的性能体验效果。可能会成为未来React Native导航组件的主流军 。
可以粗略地理解,navigation就是rn版的router。
安装
注:从19年7月到现在不到两个月,navigation有了大的更新。看官网文档也未必有用。经过笔者一天的踩坑,想要成功运行请严格执行以下操作。其它不能保证。 请确保项目绝对路径无中文。
安装(0.60-)时除了本体,还需要一个手势库:
yarn add [email protected] yarn [email protected]
接着需要手动link它(关联原生):
react-native link react-native-gesture-handler
此时ios已经可以跑了。但安卓配置还没完。把以下代码添加到 MainActivity.java
package com.rn; import com.facebook.react.ReactActivity; // add import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; // end add public class MainActivity extends ReactActivity { /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "rn"; } // add @Override protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()) { @Override protected ReactRootView createRootView() { return new RNGestureHandlerEnabledRootView(MainActivity.this); } }; } // end add }

到了这一步,就可以启动应用了。
补白
概念
在开始学习导航器之前,我们需要了了解两个和导航有关的概念:
- Screen navigation prop(屏幕导航属性):通过navigation可以完成屏幕之间的调度操作,例如打开另一个屏幕
- Screen navigationOptions(屏幕导航选项):通过navigationOptions可以定制导航器显示屏幕的方式(例如:头部标题,选项卡标签等)
导航器类型
在react-navigation中有以下类型的导航器:
- createStackNavigator:类似普通的Navigator,导航上⽅导航栏
- createTabNavigator:已弃用,使⽤createBottomTabNavigator、 createMaterialTopTabNavigator替代
- createBottomTabNavigator:相当于IOS里面的UITabBarController,屏幕下⽅的标签
- createMaterialTopTabNavigator:屏幕顶部的材料设计主题标签栏
- createDrawerNavigator:抽屉效果,侧边滑出
- createSwitchNavigator:SwitchNavigator的用途是一次只显示⼀个⻚页⾯面
你可以通过以上几种导航器来创建你的APP,可以是其中一个,也可以多个组合,这个可以根据具体的应 ⽤场景并结合每⼀个导航器器的特性进⾏选择。
项目管理
创建一个src目录,如图:

在page下写几个页面(HomePage,MyPage,HotPage):
import React,{Component} from 'react'; import {View,Text,StyleSheet} from 'react-native'; export default class HomePage extends Component{ render(){ return ( <View style={styles.container}> <Text style={styles.text}>HomePage</Text> </View> ) } } const styles=StyleSheet.create({ container:{ flex:1, justifyContent:'center', alignItems:'center', backgroundColor:'#f5f5f5' }, text:{ fontSize:26 } })
在Navigator下新建AppNavigator.js:
import {createAppContainer} from 'react-navigation'; import { createStackNavigator } from 'react-navigation-stack'; import HomePage from '../Pages/HomePage'; import MyPage from '../Pages/MyPage'; import HotPage from '../Pages/HotPage'; const AppNavigator=createStackNavigator({ Home:{ screen:HomePage }, My:{ screen:MyPage }, Hot:{ screen:HotPage } }); export default createAppContainer(AppNavigator);
跑一下程序,看到:

就算运行成功了。
基本使用(重点)
这里使用堆栈导航。
createStackNavigator 提供APP屏幕之间切换的能⼒,它是以栈的形式还管理屏幕之间的切换,新切换到的屏幕会放在栈的顶部。
createStackNavigator API
createStackNavigator(RouteConfigs, StackNavigatorConfig):
- RouteConfigs (必选):路路由配置对象是从路路由名称到路路由配置的映射,告诉导航器器该路路由呈现什什 么。
- StackNavigatorConfig (可选):配置导航器器的路路由(如:默认⾸首屏,navigationOptions,paths 等)样式(如,转场模式mode、头部模式等)。
在HomePage引入button,给它加个 onPress
事件:
<View style={styles.container}> <Button title={'跳转到我的页面'} onPress={()=>{ console.log(this.props) }} ></Button> <Text style={styles.text}>HotPage</Text> </View>
然后页面上出现一个button,点击一下,控制台弹出了以下内容:

通过navigation。封装了一系列方法。
- navigate:跳转到其他界⾯
- state:屏幕的当前state
- setParams:改变路由的params
- goBack:关闭当前屏幕
- disPatch:向路由发送一个action
- addListener:订阅导航生命周期的更新
- isFocused:true标识屏幕获取了焦点
- getParam:获取具有回退的特定参数
- dangerouslyGetParent:返回父导航器
注意:一个navigation有可能没有navigate、setParams以及goBack,只有state与dispatch,所以在使用navigate时要进⾏判断,如果没有navigate可以使⽤navigation去dispatch一个新的action。
跳转
接收两个参数,第一个是定义好的路由名,第二个是页面参数。
<Button title={'跳转到我的页面'} onPress={()=>{ console.log(this.props) this.props.navigation.navigate('My',{ title:'我的' }) }} ></Button> <Button title={'跳转到热门页面'} onPress={()=>{ console.log(this.props) this.props.navigation.navigate('Hot',{ title:'热门' }) }} ></Button> <Text style={styles.text}>HomePage</Text>

返回
留意右上角,原生按钮已经支持返回。但我想自定义一个返回按钮的话可以直接用goBack方法:
<Button title={'返回'} onPress={()=>{ this.props.navigation.goBack() }} ></Button>
goBack:function goBack(key):我们可以借助goBack返回到上⼀页或者路由栈的指定⻚面。
key标识你要返回到⻚面的⻚面标识符,如:id-1517035332238-4,不是routeName。可以通过指定⻚面的navigation.state.key来获取⻚页⾯面的标识 key必传,不传默认返回上一页
传参
现在我想定义一个参数给下一个也页面,可以这么做:
<Button title={'跳转到热门页面'} onPress={()=>{ console.log(this.props) this.props.navigation.navigate('Hot',{ title:'热门' }) }} ></Button>
在被跳转的页面可以通过getParam方法获取:
<Text style={styles.text}>{this.props.navigation.getParam('title')}</Text>
在页面中定义标题
留意到以下模拟器中,


这些都是可以自己定义的。
回到AppNavigator,我可以给首页加个标题:
Home:{ screen:HomePage, // 导航器配置: navigationOptions:{ // 让导航栏为空 // header:null // 设置导航栏标题 headerTitle:'首页' } },
优雅地定义标题
你还可以自定义navigationOptions:
export default class MyPage extends Component{ static navigationOptions={ title:'我的' } render(){ return ( <View style={styles.container}> <Text style={styles.text}>{this.props.navigation.getParam('title')}</Text> </View> ) } }
接下来可以组合页面穿参来用:
static navigationOptions=({navigation})=>{ return { headerTitle:navigation.getParam('title') } }
!image-20190914172536556
更新参数
有getParam就有setParams。
export default class MyPage extends Component{ static navigationOptions=({navigation})=>{ return { headerTitle:navigation.getParam('title') } } render(){ return ( <View style={styles.container}> <Text style={styles.text}>{this.props.navigation.getParam('title')}</Text> <Button title={'更新页面参数'} onPress={()=>{ this.props.navigation.setParams({ title:'aaa' }) }} ></Button> </View> ) } }
一点击,你的title就全变成了aaa。
注意:navigation.setParams改变的是当前页⾯的Params,如果要改变其他⻚面的Params可以通过 NavigationActions.setParams完成。