RN学习笔记之Navigator

接触了RN之后,必不可免得要接触界面之间跳转之类的需求,而这一类需求的实现必须要使用到Navigator这个导航器,这次记录一下使用过程中对于Navigator导航器的认知。

首先要理解这个导航器,可以通俗的理解和Android中activity的堆栈管理一样,导航器除了界面导航功能之外,还提供界面栈的管理,界面的跳入和跳出。(RN中每一个component都相当于一个组件,一个或多个component共同构成场景(Scene),场景通俗的理解就是一个占据整个屏幕的界面)

RN中的入口是index.android.js(以Android为例),这个index.js可以看成整个RN组建的框架,一些基础的东西都在这里实例化、定义。我们的导航器也需要在这个文件中被创建。(后文中提到的BackAndroid也在这里面定义)

Navigator属性介绍

Navigator中包含如下属性:

initialRoute

初始化路由,初始化需要显示的Component,其中的component参数必须要有,定义如下:

initialRoute={{title:'main',id:'main',component:defaultComponent}}

configureScene

配置场景动画,系统提供了很多动画,如从底部弹出,从左弹出等,参数如下:

组件中定义:

configureScene={this._configureScence.bind(this)}


_configureScence(route) {

console.log("AndroidTestComponent=====configureScenceAndroid"+ route.type)

if(route.type =='Bottom') {

returnNavigator.SceneConfigs.FloatFromBottom;// 底部弹出

}else if(route.type =='Left') {

returnNavigator.SceneConfigs.FloatFromLeft// 右侧弹出

}else if(route.type =='Right') {

returnNavigator.SceneConfigs.FloatFromRight//左侧弹出

}

returnNavigator.SceneConfigs.PushFromRight;// 默认右侧弹出

}

renderScene

场景渲染,根据路由来确定要挂载渲染的场景,设置如下:

组件中定义

renderScene={this._scene.bind(this)}


//场景渲染方法,传入路由器和导航器两个方法

_scene(route, navigator) {

console.log(route)

//这个里面如果不做处理,默认返回的是initialRoute初始化的component

letComponent= route.component;

//路由器的params可以携带参数

//将改导航器传递给下一个Component

return

//或者直接引入一个现成的Component

//return

}

ref

这个属性有点很微妙,网上很多介绍Navigator的博客代码中没有写这个属性,这个属性相当于给一个组件添加一个label标签,然后通过该标签可以找到对应的组件,发现这个属性的原因是我在写BackAndroid的时候,需要使用到navigator这个对象,在监听物理返回键的时候判断是否还有路由存在,通常在方法中获取navigator的方法如下:

_pressButton(){

const {navigator} = this.props;

}

这么写的前提是_pressButton该方法一般都会被bind,而且该Component在挂载前已经把navigator传递过来了,所以可以获得到,但是我们在index.js中使用BackAndroid,定义方法不管是使用箭头函数或者在构造方法中bind对应的方法,这个时候this.props都没有navigator这个属性,所以这个时候是找不到的,也就没办法实现导航回退的功能,而使用ref就很好的解决这个问题了,即子组件获取父组件通过props、父组件获取子组件通过refs。如下设置:

在组建中添加:

ref="navigator"

方法中调用:

onBackAndroid=()=>{

constnavigator=this.refs.navigator;

...

}

Navigator方法

getCurrentRoutes() - 获取当前栈里的路由列表,也就是push进来,没有pop掉的那些

jumpBack() - 跳回之前的路由,保留现在的,还可以再跳回来。相当于浏览器的回退

jumpForward() - 结合jumpBack,此方法再重新打开回退前的,相当于浏览器的前进

jumpTo(route) - 跳转到一个没有被取消挂载的已存在场景

push(route) - push一个新的路由场景

pop() - 移除并取消挂载当前的场景,回到上一个场景

replace(route) -用一个新的路由场景替代当前的场景,该方法之后当前的场景就被取消挂载了

replaceAtIndex(route,index) -通过制定index下标replace

replacePrevious(route) -replace前一个场景

immediatelyResetRouteStack(routeStack) -用新的路由场景Stack重置堆栈中的每一个场景

popToRoute(route) - 移除并取消挂载当前场景到制定场景之间的对

popToTop() - 移除并取消挂载出堆栈中第一个场景外的其他场景

其中route路由最基本的就是

var route = {component: LoginComponent}


完整代码如下

//component是从react中来的

importReact, {Component}from'react';

//Text以及View等都是从react-native中来的

import{

AppRegistry,

StyleSheet,

Navigator,

BackAndroid,

Dimensions

}from'react-native';

importsplashfrom'./app/mainview/splash'

importguidefrom'./app/mainview/guide'

//定义一个Component,按照ES6的语法来,就和java语法中定义class一样,继承component

export  default  classAndroidTestComponentextendsComponent{

//构造函数

constructor(props) {

super(props)

//如果_onBackAndroid不是一个箭头函数,需要在构造函数中bind this,要不然在添加监听和移除监听时操作的对象是不同的

// this._onBackAndroid = this.onBackAndroid.bind(this)

}

//场景动画

_configureScence(route) {

console.log("AndroidTestComponent=====configureScenceAndroid"+ route.type)

if(route.type =='Bottom') {

returnNavigator.SceneConfigs.FloatFromBottom;// 底部弹出

}else if(route.type =='Left') {

returnNavigator.SceneConfigs.FloatFromLeft// 右侧弹出

}else if(route.type =='Right') {

returnNavigator.SceneConfigs.FloatFromRight//左侧弹出

}

returnNavigator.SceneConfigs.PushFromRight;// 默认右侧弹出

}

//场景渲染

_scene(route, navigator) {

letComponent= route.component;

//传递参数以及导航器

return

}

//使用箭头函数,直接绑定this,不需要再构造函数中再去bind

onBackAndroid=()=>{

//使用refs来获取导航器

constnavigator=this.refs.navigator;

if(!navigator){

return false;

}

constrouters=navigator.getCurrentRoutes();

if(routers.length>1){

navigator.pop();

return true;

}else{

return false;

}

}

//compoment将要挂载的函数,这个时候可以在继续更新state 添加监听

componentWillMount() {

console.log("AndroidTestComponent=====componentWillMount")

BackAndroid.addEventListener('hardwareBackPress',this.onBackAndroid)

}

//render属性对应的函数会返回一段JSX来表示该组件的结构和布局。该部分是一个组件必不可少的地方,没有这些内容,就无法构成一个组件。

//render方法必须返回单个根元素

//compoment挂载渲染的函数

render() {

//定义默认闪屏界面

letdefaultComponent= splash;

return(

configureScene={this._configureScence.bind(this)}

renderScene={this._scene.bind(this)}

ref="navigator"

/>

);

}

//compoment已经挂载的函数

//界面渲染完之后,在进行一些数据处理,比如网络数据加载,比如本地数据加载

componentDidMount() {

console.log("AndroidTestComponent=====componentDidMount")

}

//作为子控件时,当期属性被改变时调用

componentWillReceiveProps(nextProps) {

console.log("AndroidTestComponent=====componentWillReceiveProps")

}

//component将要更新时调用

componentWillUpdate(nextProps, nextState) {

console.log("AndroidTestComponent=====componentWillUpdate")

}

//component更新后调用

componentDidUpdate(prevProps, prevState) {

console.log("AndroidTestComponent=====componentDidUpdate")

}

//component销毁时调用

componentWillUnmount() {

console.log("AndroidTestComponent=====componentWillUnmount")

BackAndroid.removeEventListener('hardwareBackPress',this.onBackAndroid)

}

}

conststyles=StyleSheet.create({

container: {

flex:1,

justifyContent:'flex-start',

alignItems:'stretch',

backgroundColor:'white'

},

lineStyle: {

backgroundColor:'grey',

height:0.3,

},

loadText: {

fontSize:20,

textAlign:'center',

margin:10

},

loadView: {

flex:1,

alignItems:'center',

justifyContent:'center'

},

});

//另一种定义props的方法,如果static defaultProps也定义了,这个会覆盖上面的

// AndroidTestComponent.defaultProps = {

//    name:'xiaoerlang'

// }

//进行注册 'RNProject'为项目名称 AndroidTestComponent 为启动的component

AppRegistry.registerComponent('RNProject', () => AndroidTestComponent);

过程中遇到的问题及解决方案:

react native - expected acomponent class, got [object Object]

该错误是引用了小写的组件,组件首字母一定要大写,比如<splash/>应该写成<Splash>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人...
    珍此良辰阅读 7,267评论 33 15
  • 一.简介 使用导航器可以让你在应用的不同场景(页面)间进行切换。导航器通过路由对象来分辨不同的场景。利用rende...
    飞奔的小马阅读 796评论 0 0
  • 早应过了彷徨的年纪,却遭遇令人感伤的细雨,也许有意或许无意的话语,触动已收藏起来的情感记忆,久久不能平息。 若...
    菩集阅读 228评论 0 0
  • 中国有句古话叫礼尚往来,但有些时候礼尚往来却厚重的有来无往。礼尚往来是一种和谐的状态,是彼此惺惺相惜的平等尊重,是...
    昏尘居士阅读 269评论 0 1
  • 文静 雨一路狂奔, 只为思太久,念太执。 好急,好急, 就这样扎入妈妈的怀里。 大地用干裂的手抚摸雨滴, 我也想你...
    文静_5c0c阅读 327评论 4 10