金沙棋牌官方平台

当前位置:金沙棋牌 > 金沙棋牌官方平台 > ReactNative学习实践,使用导航Navigator

ReactNative学习实践,使用导航Navigator

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-11-05 18:52

ReactNative学习实践:Navigator实践

2016/06/17 · JavaScript · HTML5, Javascript, React, ReactNative

本文作者: 伯乐在线 - D.son 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

离上次写RN笔记有一段时间了,期间参与了一个新项目,只在最近的空余时间继续学习实践,因此进度比较缓慢,不过这并不代表没有新进展,其实这个小东西离上次发文时已经有了相当大的变化了,其中影响最大的变化就是引入了Redux,后面会系统介绍一下。
在开始主题之前,先补充一点上回说到的动画初探(像我这么靠谱严谨的攻城狮,必须精益求精,┗|`O′|┛ 嗷~~)。

上回文说到,经过我们自己定义了余弦动画函数之后,动态设定state的4个参数,实现了比较流畅的加载动画,这里可能有朋友已经注意到了,我们非常频繁的调用了setState方法,这在React和RN中都是相当忌讳的,每一次setState都会触发render方法,也就意味着更频繁的虚拟DOM对比,特别是在RN中,这还意味着更频繁的JSCore<==>iOS通信,尽管框架本身对多次setState做了优化,比如会合并同时调用的多个setState,但这对性能和体验还是会有较大影响。

上回我们只是单独实现了一个loading动画,所以还比较流畅,当视图中元素较多并且有各自的动画的时候,就会看到比较严重的卡顿,这些其实是可以避免的,因为在loading动画的实现部分,我们清楚地知道只需要loading动画的特定组成部分更新而不是组件的所有部分以及继承链上的所有组件都需要更新,并且确信这个节点一定发生了变化,因此不需要经过虚拟DOM对比,那么如果我们能绕开setState,动画就应该会更流畅,即使在复杂的视图里边。这就是Animations文档最后提到的setNativeProps方法。

As mentioned in the Direction Manipulation section, setNativeProps allows us to modify properties of native-backed components (components that are actually backed by native views, unlike composite components) directly, without having to setState and re-render the component hierarchy.

setNativeProps允许我们直接操纵原生组件的属性,而不需要用到setState,也不会重绘继承链上的其他组件。这正是我们想要的效果,加上我们明确知道正在操纵的组件以及它与视图其他组件的关系,因此,这里我们可以放心地使用它,而且相当简单。
更新前:

loopAnimation(){ var t0=animationT,t1=t0+0.5,t2=t1+0.5,t3=t2+timeDelay,t4=t3+0.5;//这里分别是四个动画的当前时间,依次加上了0.5的延迟 var v1=Number(Math.cos(t0).toFixed(2))*animationN+animationM;//将cos函数的小数值只精确到小数点2位,提高运算效率 var v2=Number(Math.cos(t1).toFixed(2))*animationN+animationM; var v3=Number(Math.cos(t2).toFixed(2))*animationN+animationM; var v4=Number(Math.cos(t3).toFixed(2))*金沙棋牌官方平台,animationN+animationM; this.setState({ fV:v1, sV:v2, tV:v3, foV:v4 }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
loopAnimation(){
    var t0=animationT,t1=t0+0.5,t2=t1+0.5,t3=t2+timeDelay,t4=t3+0.5;//这里分别是四个动画的当前时间,依次加上了0.5的延迟
    var v1=Number(Math.cos(t0).toFixed(2))*animationN+animationM;//将cos函数的小数值只精确到小数点2位,提高运算效率
    var v2=Number(Math.cos(t1).toFixed(2))*animationN+animationM;
    var v3=Number(Math.cos(t2).toFixed(2))*animationN+animationM;
    var v4=Number(Math.cos(t3).toFixed(2))*animationN+animationM;
    this.setState({
      fV:v1,
      sV:v2,
      tV:v3,
      foV:v4
    });
    animationT+=0.35;//增加时间值,每次增值越大动画越快
    requestAnimationFrame(this.loopAnimation.bind(this));
  }

更新后:

loopAnimation(){ var t0=··· var v1=··· var v2=··· var v3=··· var v4=··· this.refs.line1.setNativeProps({ style:{width:w1,height:v1} }); this.refs.line2.setNativeProps({ style:{width:w2,height:v2} }); this.refs.line3.setNativeProps({ style:{width:w3,height:v3} }); this.refs.line4.setNativeProps({ style:{width:w4,height:v4} }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
loopAnimation(){
    var t0=···
    var v1=···
    var v2=···
    var v3=···
    var v4=···
    this.refs.line1.setNativeProps({
      style:{width:w1,height:v1}
    });
    this.refs.line2.setNativeProps({
      style:{width:w2,height:v2}
    });
    this.refs.line3.setNativeProps({
      style:{width:w3,height:v3}
    });
    this.refs.line4.setNativeProps({
      style:{width:w4,height:v4}
    });
    animationT+=0.35;//增加时间值,每次增值越大动画越快
    requestAnimationFrame(this.loopAnimation.bind(this));
  }

效果如下:
金沙棋牌官方平台 1
这里有意在注册请求完毕之后没有隐藏loading动画,因此同时执行了视图切换和loading两个动画,效果还行~

好了,该进入今天的正题了。先整体看一下这一阶段实现的效果(哒哒哒~):
金沙棋牌官方平台 2

主要是模拟了一个新用户注册流程,实现起来也并不复杂,整体结构是用一个RN组件Navigator来做导航,虽然有另一个NavigatorIOS组件在iOS系统上表现更加优异,但是考虑到RN本身希望能够同时在安卓和iOS上运行的初衷,我选择了可以兼容两个平台的Navigator来尝试,目前来看效果还能接受。
在最后的详细信息视图里边,尝试了各种组件,比如调用相机,Switch,Slider等,主要是尝鲜,哈哈~ 也自己实现了比较简单的check按钮。
首先最外层的结构是一个Navigator,它控制整个用户注册的视图切换:

<Navigator style={styles.navWrap} initialRoute={{name: 'login', component:LoginView}} configureScene={(route) => { return Navigator.SceneConfigs.FloatFromRight; }} renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} navigator={navigator} /> }} />

1
2
3
4
5
6
7
8
9
<Navigator style={styles.navWrap}
          initialRoute={{name: 'login', component:LoginView}}
          configureScene={(route) => {
            return Navigator.SceneConfigs.FloatFromRight;
          }}
          renderScene={(route, navigator) => {
            let Component = route.component;
            return <Component {...route.params} navigator={navigator} />
          }} />

其中,initialRoute配置了Navigator的初始组件,这里就是LoginView组件,它本身既可以直接登录,也可以点击【我要注册】进入注册流程。configureScene属性则是用来配置Navigator中视图切换的动画类型,这里可以灵活配置切换方式:

Navigator.SceneConfigs.PushFromRight (default) Navigator.SceneConfigs.FloatFromRight Navigator.SceneConfigs.FloatFromLeft Navigator.SceneConfigs.FloatFromBottom Navigator.SceneConfigs.FloatFromBottomAndroid Navigator.SceneConfigs.FadeAndroid Navigator.SceneConfigs.HorizontalSwipeJump Navigator.SceneConfigs.HorizontalSwipeJumpFromRight Navigator.SceneConfigs.VerticalUpSwipeJump Navigator.SceneConfigs.VerticalDownSwipeJump

1
2
3
4
5
6
7
8
9
10
Navigator.SceneConfigs.PushFromRight (default)
Navigator.SceneConfigs.FloatFromRight
Navigator.SceneConfigs.FloatFromLeft
Navigator.SceneConfigs.FloatFromBottom
Navigator.SceneConfigs.FloatFromBottomAndroid
Navigator.SceneConfigs.FadeAndroid
Navigator.SceneConfigs.HorizontalSwipeJump
Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
Navigator.SceneConfigs.VerticalUpSwipeJump
Navigator.SceneConfigs.VerticalDownSwipeJump

renderScene属性则是必须配置的一个属性,它负责渲染给定路由对应的组件,也就是向Navigator所有路由对应的组件传递了”navigator”属性以及route本身携带的参数,如果不使用类似Flux或者Redux来全局存储或控制state的话,那么Navigator里数据的传递就全靠”route.params”了,比如用户注册流程中,首先是选择角色视图,然后进入注册视图填写账号密码短信码等,此时点击注册才会将所有数据发送给服务器,因此从角色选择视图到注册视图,需要将用户选择的角色传递下去,在注册视图发送给服务器。因此,角色选择视图的跳转事件需要把参数传递下去:

class CharacterView extends Component { constructor(props){ super(props); this.state={ character:"type_one" } } handleNavBack(){ this.props.navigator.pop(); } ··· handleConfirm(){ this.props.navigator.push({ name:"registerNav", component:RegisterNavView, params:{character:this.state.character} }); } render(){ return ( <View style={styles.container}> <TopBarView title="注册" hasBackArr={true} onBackPress={this.handleNavBack.bind(this)}/> ··· (this)}> 确认> </TouchableOpacity> > </View> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class CharacterView extends Component {
  constructor(props){
    super(props);
    this.state={
        character:"type_one"
    }
  }
 
  handleNavBack(){
    this.props.navigator.pop();
  }
  
  ···
  
  handleConfirm(){
    this.props.navigator.push({
      name:"registerNav",
      component:RegisterNavView,
      params:{character:this.state.character}
    });
  }
 
  render(){
    return (
      <View style={styles.container}>
        <TopBarView title="注册" hasBackArr={true} onBackPress={this.handleNavBack.bind(this)}/>
        
          
          ···
          
          (this)}>
            确认>
          </TouchableOpacity>
        >
      </View>
    );
  }
}

这是角色选择视图CharacterView的部分代码,由于Navigator并没有像NavigatorIOS那样提供可配置的顶栏、返回按钮,所以我把顶栏做成了一个克配置的公共组件TopBarView,Navigator里边的所有视图直接使用就可以了,点击TopBarView的返回按钮时,TopBarView会调用给它配置的onBackPress回调函数,这里onBackPress回调函数是CharacterView的handleNavBack方法,即执行了:

this.props.navigator.pop();

1
this.props.navigator.pop();

关于this.props.navigator,这里我们并没有在导航链上的每个组件显式地传递navigator属性,而是在Navigator初始化的时候就在renderScene属性方法里统一配置了,导航链上所有组件的this.props.navigator其实都指向了一个统一的navigator对象,它有两个方法:push和pop,用来向导航链压入和推出组件,视觉上就是进入下一视图和返回上一视图,因此这里当点击顶栏返回按钮时,直接调用pop方法就返回上一视图了。其实也可以把navigator对象传递到TopBarView里,在TopBarView内部调用navigator的pop方法,原理是一样的。而在CharacterView的确认按钮事件里,需要保存用户选择的角色然后跳转到下一个视图,就是通过props传递的:

this.props.navigator.push({ name:"registerNav", component:RegisterNavView, params:{character:this.state.character} });

1
2
3
4
5
this.props.navigator.push({
      name:"registerNav",
      component:RegisterNavView,
      params:{character:this.state.character}
    });

这里就是调用的navigator属性的push方法向导航链压入新的组件,即进入下一视图。push方法接收的参数是一个包含三个属性的对象,name只是用来标识组件名称,而commponent和params则是标识组件以及传递给该组件的参数对象,这里的”commponent”和”params”两个key名称是和前面renderScene是对应的,在renderScene回调里边,用到的route.commponent和route.params,就是这里push传递的参数对应的值。
在用户注册视图中,有一个用户协议需要用户确认,这里用户协议视图的切换方式与主流程不太一样,而一个Navigator只能在最初配置一种切换方式,因此,这里在Navigator里嵌套了Navigator,效果如下:
金沙棋牌官方平台 3
CharacterView的跳转事件中,向navigator的push传递的组件并不是RegisterView组件,而是传递的RegisterNavView组件,它是被嵌套的一个Navigator,这个子导航链上包含了用户注册视图及用户协议视图。

class RegisterNavView extends Component { constructor(props){ super(props); } handleConfirm(){ //send data to server ··· // this.props.navigator.push({ component:nextView, name:'userInfo' }); } render(){ return ( <View style={styles.container}> <Navigator style={styles.navWrap} initialRoute={{name: 'register', component:RegisterView,params:{navigator:this.props.navigator,onConfirm:this.handleConfirm.bind(this)}}} configureScene={(route) => { return Navigator.SceneConfigs.FloatFromBottom; }} renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} innerNavigator={navigator} /> }} /> </View> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class RegisterNavView extends Component {
  constructor(props){
    super(props);
  }
 
  handleConfirm(){
    //send data to server
    ···
    //
    this.props.navigator.push({
        component:nextView,
        name:'userInfo'
      });
  }
 
  render(){
    return (
      <View style={styles.container}>
        <Navigator style={styles.navWrap}
          initialRoute={{name: 'register', component:RegisterView,params:{navigator:this.props.navigator,onConfirm:this.handleConfirm.bind(this)}}}
          configureScene={(route) => {
            return Navigator.SceneConfigs.FloatFromBottom;
          }}
          renderScene={(route, navigator) => {
            let Component = route.component;
            return <Component {...route.params} innerNavigator={navigator} />
          }} />
      </View>
    );
  }
}

这个被嵌套的导航我们暂且称为InnerNav,它的初始路由组件就是RegisterView,展示了输入账号密码等信息的视图,它的configureScene设置为“FloatFromBottom”,即从底部浮上来,renderScene也略微不一样,在InnerNav导航链组件上传递的navigator对象名称改成了innerNavigator,以区别主流程Navigator,在RegisterView中有一个【用户协议】的文字按钮,在这个按钮上我们调用了向InnerNav压入协议视图的方法:

handleShowUserdoc(){ this.props.innerNavigator.push({ name:"usrdoc", component:RegisterUsrDocView }); }

1
2
3
4
5
6
handleShowUserdoc(){
    this.props.innerNavigator.push({
      name:"usrdoc",
      component:RegisterUsrDocView
    });
  }

而在RegisterUsrDocView即用户协议视图组件中,点击确定按钮时我们调用了从InnerNav推出视图的方法:

handleHideUserdoc(){ this.props.innerNavigator.pop(); }

1
2
3
handleHideUserdoc(){
    this.props.innerNavigator.pop();
}

这样内嵌的导航链上的视图就完成了压入和推出的完整功能,如果有需要,还可以添加更多组件。
在RegisterNavView组件的handleConfirm方法中,也就是点击注册之后调用的方法,此时向服务器发送数据并且需要进入注册的下一环节了,因此需要主流程的Navigator压入新的视图,所以调用的是this.props.navigator.push,而不是innderNavigator的方法。

好了,大概结构和流程就介绍到这里了,相对比较简单,实际开发中还是会遇到很多细节问题,比如整个注册流程中,数据都需要存储在本地,最后统一提交到服务器,如果导航链上有很多组件,那么数据就要一级一级以props的方式传递,非常蛋疼,因此才引入了Redux来统一存储和管理,下一篇文章会系统介绍Redux以及在这个小项目里引入Redux的过程。

打赏支持我写出更多好文章,谢谢!

打赏作者

一、Navigator

Navigator 导航器

下面是一个简单的例子,用Navigator来跳转页面,页面之间传递参数 (代码是ES6语法写的):

 import React from 'react';
    import {
        View,
        Navigator
    } from 'react-native';
    import FirstPageComponent from './FirstPageComponent';

    export default class SampleComponent extends React.Component {
        render() {
            let defaultName = 'FirstPageComponent';
            let defaultComponent = FirstPageComponent;
            return (
            <Navigator
              initialRoute={{ name: defaultName, component: defaultComponent }}
              configureScene={(route) => {
                return Navigator.SceneConfigs.VerticalDownSwipeJump;
              }}
              renderScene={(route, navigator) => {
                let Component = route.component;
                return <Component {...route.params} navigator={navigator} />
              }} />
            );
        }
    } 

这里来解释一下代码:

第三行: 一个初始首页的component名字,比如我写了一个component叫HomeComponent,那么这个name就是这个组件的名字【HomeComponent】了。

第四行: 这个组件的Class,用来一会儿实例化成 <Component />标签

第七行: initialRoute={{ name: defaultName, component: defaultComponent }} 这个指定了默认的页面,也就是启动app之后会看到界面的第一屏。 需要填写两个参数: name 跟 component。(注意这里填什么参数纯粹是自定义的,因为这个参数也是你自己发自己收,自己在renderScene方法中处理。我们这里示例用了两个参数,但其实真正使用的参数只有component)

第八,九,十行: configureScene={() => {
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}} 这个是页面之间跳转时候的动画,具体有哪些?可以看这个目录下,有源代码的: node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js

最后的几行: renderScene={(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}} />
);

这里是每个人最疑惑的,我们先看到回调里的两个参数:route, navigator。通过打印我们发现route里其实就是我们传递的name,component这两个货,navigator是一个Navigator的对象,为什么呢,因为它有push pop jump...等方法,这是我们等下用来跳转页面用的那个navigator对象。

return <Component {...route.params} navigator={navigator} />

这里有一个判断,也就是如果传递进来的component存在,那我们就是返回一个这个component,结合前面 initialRoute 的参数,我们就是知道,这是一个会被render出来给用户看到的component,然后navigator作为props传递给了这个component。

所以下一步,在这个FirstPageComponent里面,我们可以直接拿到这个 props.navigator:

import React from 'react';
import {
    View,
    Navigator
} from 'react-native';

import SecondPageComponent from './SecondPageComponent';

export default class FirstPageComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {};
    }
    _pressButton() {
        const { navigator } = this.props;
        //为什么这里可以取得 props.navigator?请看上文:
        //<Component {...route.params} navigator={navigator} />
        //这里传递了navigator作为props
        if(navigator) {
            navigator.push({
                name: 'SecondPageComponent',
                component: SecondPageComponent,
            })
        }
    }
    render() {
        return (
            <View>
                <TouchableOpacity onPress={this._pressButton.bind(this)}>
                    <Text>点我跳转</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

这个里面创建了一个可以点击的区域,让我们点击可以跳到SecondPageComponent这个页面,实现页面的跳转。
现在来创建SecondPageComponent,并且让它可以再跳回FirstPageComponent:

import React from 'react';

 constructor(props) {
        super(props);
        this.state = {};
    }

    _pressButton() {
        const { navigator } = this.props;
        if(navigator) {
            //很熟悉吧,入栈出栈~ 把当前的页面pop掉,这里就返回到了上一个页面:FirstPageComponent了
            navigator.pop();
        }
    }

    render() {
    return (
            <View>
                <TouchableOpacity onPress={this._pressButton.bind(this)}>
                    <Text>点我跳回去</Text>
                </TouchableOpacity>
            </View>
    );
    }
}

大功告成,能进能出了。

关于官方文档里有个东西,这里说一下:

getCurrentRoutes() - 获取当前栈里的路由,也就是push进来,没有pop掉的那些
jumpBack() - 跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。
jumpForward() - 上一个方法不是调到之前的路由了么,用这个跳回来就好了
jumpTo(route) - Transition to an existing scene without unmounting
push(route) - Navigate forward to a new scene, squashing any scenes that you could jumpForward to
pop() - Transition back and unmount the current scene
replace(route) - Replace the current scene with a new route
replaceAtIndex(route, index) - Replace a scene as specified by an index
replacePrevious(route) - Replace the previous scene
immediatelyResetRouteStack(routeStack) - Reset every scene with an array of routes
popToRoute(route) - Pop to a particular scene, as specified by its route. All scenes after it will be unmounted
popToTop() - Pop to the first scene in the stack, unmounting every other scene

这些都是navigator可以用的public method,就是跳转用的,里面有些带参数的XXX(route),新手第一次看这个文档会疑惑,这个route参数是啥呢,这个route就是:

renderScene={(route, navigator) => 

这里的route,最基本的route就是:

var route = {
    component: LoginComponent
}

这种格式。这个地方有点模糊的,在这里先说清楚了。

然后下面要讨论,怎么传递参数过去,或者从对方获取参数。
传递参数,通过push就可以了。
比如在一个 press的事件里:

//FirstPageComponent.js
import React from 'react';
import {
    View,
    Navigator
} from 'react-native';

import SecondPageComponent from './SecondPageComponent';

export default class FirstPageComponent extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            id: 2
        };
    }


    _pressButton() {
        const { navigator } = this.props;
        if(navigator) {
            navigator.push({
                name: 'SecondPageComponent',
                component: SecondPageComponent,
                //这里多出了一个 params 其实来自于<Navigator 里的一个方法的参数...
                params: {
                    id: this.state.id
                }
            });
        }
    }

    render() {
        return (
            <View>
                <TouchableOpacity onPress={this._pressButton.bind(this)}>
                    <Text>点我跳转并传递id</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

params的来历:

// index.ios.js
<Navigator
  initialRoute={{ name: defaultName, component: defaultComponent }}
  configureScene={() => {
    return Navigator.SceneConfigs.VerticalDownSwipeJump;
  }}
  renderScene={(route, navigator) => {
    let Component = route.component;
    if(route.component) {
        //这里有个 { ...route.params }
        return <Component {...route.params} navigator={navigator} />
    }
  }} />
这个语法是把 routes.params 里的每个key 作为props的一个属性:

navigator.push({
    name: 'SecondPageComponent',
    component: SecondPageComponent,
    params: {
        id: this.state.id
    }
});

这里的 params.id 就变成了 <Navigator id={} 传递给了下一个页面。所以 SecondPageComponent就应该这样取得 id:

//SecondPageComponent.js
import React from 'react';
import {
   View,
   Navigator
} from 'react-native';

import FirstPageComponent from './FirstPageComponent';

export default class SecondPageComponent extends React.Component {

   constructor(props) {
       super(props);
       this.state = {
           id: null
       }
   }

   componentDidMount() {
       //这里获取从FirstPageComponent传递过来的参数: id
       this.setState({
           id: this.props.id
       });
   }

   _pressButton() {
       const { navigator } = this.props;
       if(navigator) {
           navigator.pop();
       }
   }

   render() {
       return (
           <View>
               <Text>获得的参数: id={ this.state.id }</Text>
               <TouchableOpacity onPress={this._pressButton.bind(this)}>
                   <Text>点我跳回去</Text>
               </TouchableOpacity>
           </View>
       );
   }
}

这样在页面间传递的参数,就可以获取了。

@sunnylqm 很多人不理解这里的params,我忍不住稍微补充一下。

金沙棋牌官方平台 4

0_1453170797112_QQ图片20160119102616.png

然后就是返回的时候,也需要传递参数回上一个页面:
但是navigator.pop()并没有提供参数,因为pop()只是从 [路由1,路由2,路由3。。。]里把最后一个路由踢出去的操作,并不支持传递参数给倒数第二个路由,这里要用到一个概念,把上一个页面的实例或者回调方法,作为参数传递到当前页面来,在当前页面操作上一个页面的state:

这是一个查询用户信息的例子,FirstPageComponent传递id到SecondPageComponent,然后SecondPageComponent返回user信息给FirstPageComponent

//FirstPageComponent.js
import React from 'react';
import {
    View,
    Navigator
} from 'react-native';

import SecondPageComponent from './SecondPageComponent';

export default class FirstPageComponent extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            id: 2,
        user: null,
        }
    }


    _pressButton() {
        let _this = this;
        const { navigator } = this.props;
        if(navigator) {
            navigator.push({
                name: 'SecondPageComponent',
                component: SecondPageComponent,
                params: {
                    id: this.state.id,
                    //从SecondPageComponent获取user
                    getUser: function(user) {
                        _this.setState({
                            user: user
                        })
                    }
                }
            });
        }
    }

    render() {
        if( this.state.user ) {
            return(
                <View>
                    <Text>用户信息: { JSON.stringify(this.state.user) }</Text>
                </View>
            );
        }else {
            return(
                <View>
                    <TouchableOpacity onPress={this._pressButton.bind(this)}>
                        <Text>查询ID为{ this.state.id }的用户信息</Text>
                    </TouchableOpacity>
                </View>
            );
        }

    }
}

然后再操作SecondPageComponent:
//SecondPageComponent.jsconst USER_MODELS = { 1: { name: 'mot', age: 23 }, 2: { name: '晴明大大', age: 25 }};import React from 'react';import { View, Navigator} from 'react-native';import FirstPageComponent from './FirstPageComponent';export default class SecondPageComponent extends React.Component { constructor(props) { super(props); this.state = { id: null } } componentDidMount() { //这里获取从FirstPageComponent传递过来的参数: id this.setState({ id: this.props.id }); } _pressButton() { const { navigator } = this.props; if(this.props.getUser) { let user = USER_MODELS[this.props.id]; this.props.getUser(user); } if(navigator) { navigator.pop(); } } render() { return( <View> <Text>获得的参数: id={ this.state.id }</Text> <TouchableOpacity onPress={this._pressButton.bind(this)}> <Text>点我跳回去</Text> </TouchableOpacity> </View> ); }}

看下效果如何吧。
放个类似的例子代码: [https://github.com/mozillo/navigation](https://github.com/mozillo/navigation)安装方法: npm install && react-native run-android

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

金沙棋牌官方平台 5 金沙棋牌官方平台 6

1 赞 3 收藏 评论

1、简单介绍:大多数时候我们都需要导航器来应对不同场景(页面)间的切换。它通过路由对象来分辨不同的场景,我们这里采用的就是renderScene方法,根据指定的路由来渲染。

从当前场景跳转到下一级场景,带转场动画

关于作者:D.son

金沙棋牌官方平台 7

80后码农兼伪文青一枚,闷骚而不木讷,猥琐不流浪荡 个人主页 · 我的文章 · 1

金沙棋牌官方平台 8

2、利用Navigator弹出用到的方法:

import React, { Component } from 'react';

(1initialRoute={{ name: 'home', component: HomeScene }} 这个指定了默认的页面,也就是启动的组件页面

import {

(2configureScene={() => {

AppRegistry,

return Navigator.SceneConfigs.HorizontalSwipeJump;

StyleSheet,

}}

Text,

这个是页面之间跳转时候的动画,可以看这个目录:

View,

node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js(可以看其他跳转的时候的方向)

Navigator,

(3renderScene:两个参数中的route包含的事initial的时候传递的name和component,而navigator是一个我们需要用的Navigator的对象,所以当我们拿到route中的component的时候,我们就可以将navigator传递给它,正因为如此,我们的组件HomeScene才可以通过this.props.navigator,拿到路由。

TouchableOpacity

(4 如果需要传参数,则在push的参数后面加多一个参数params,把JSON往死填就好了,这里的params,其实就是在renderScene中return的{...route.params},这样接收的页面只需要通过this.props.id,就可以拿到我们传递的参数

} from 'react-native';

(5 OK,那参数怎么回传呢?回调!通过定义一个回调函数,利用this.props 去调用,把参数回传回来

//第一个场景

完整代码:

var FirstScene=React.createClass({

/**

pressPush:function()

* Sample React Native App

{ //推出下一级别页面

*

var nextScene={component:SecondScene};

*/'use strict';varReact = require('react-native');//增加NavigatorIOSvar{  AppRegistry,  StyleSheet,  Text,  View,  Navigator,  TouchableHighlight,} = React;/*--  启动组件 --*/varMainClass = React.createClass({  render:function() {//component这里设置的是这个组件启动的时候显示的第一个子组件return({              return Navigator.SceneConfigs.HorizontalSwipeJump;          }}          renderScene={(route, navigator) => {            let Component = route.component;            if(route.component) {              return}          }} >);  },});/*--  首页页面组件 --*/var HomeScene = React.createClass({  getInitialState:function () {    return {      id: 'AXIBA001',      flag: null    };  },  render: function() {    return (push me!{this.state.flag && ' I 'm ' + this.state.flag + ', i come from second page'});  },  onPress: function() {    var _me = this;    //或者写成 const navigator = this.props.navigator;    const { navigator } = this.props;    if(navigator)    {        navigator.push({            name: 'touch View',            component: SecondScene,            params: {                id: this.state.id,                getSomething:function(flag) {                  _me.setState({                    flag: flag                  });                }            }        })    }  }});/*--  push后的页面组件 --*/var SecondScene = React.createClass({  render: function() {    return (push sucess!I get {this.props.id},i want back!);  },  onPress: function() {    //或者写成 const navigator = this.props.navigator;    const { navigator } = this.props;    if(this.props.getSomething) {      var flag = 'Axiba002'      this.props.getSomething(flag);    }    if(navigator) {      navigator.pop();    }  }});/*布局样式*/var styles = StyleSheet.create({  container: {    flex: 1,    // justifyContent: 'center',    // alignItems: 'center',    backgroundColor: '#F5FCFF',  },  home: {    paddingTop:74,  },});AppRegistry.registerComponent('AwesonProject', () => MainClass);

this.props.navigator.push(nextScene);

补充一些可能会用到的Navigator方法:

},

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

render(){

jumpBack() - 跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。

return(

jumpForward() - 上一个方法不是调到之前的路由了么,用这个跳回来就好了。

Go NextPage

jumpTo(route) - 跳转到已有的场景并且不卸载。

);

push(route) - 跳转到新的场景,并且将场景入栈,你可以稍后跳转过去

}

pop() - 跳转回去并且卸载掉当前场景

});

replace(route) - 用一个新的路由替换掉当前场景

//第二场景

replaceAtIndex(route, index) - 替换掉指定序列的路由场景

var SecondScene=React.createClass({

replacePrevious(route) - 替换掉之前的场景

pressPop:function()

immediatelyResetRouteStack(routeStack) - 用新的路由数组来重置路由栈

{ //返回上一级页面

popToRoute(route) - pop到路由指定的场景,其他的场景将会卸载。

//var prevScene={componment:FirstScene};

popToTop() - pop到栈中的第一个场景,卸载掉所有的其他场景。

this.props.navigator.pop();       //直接返回上一级页面不需要pop参数

二、NavigatorIOS

},

1、NavigatorIOS包装了UIKit的导航功能,可以使用左划功能来返回到上一界面。

render(){

2、同上包含的方法有:

return(

push(route)- 导航器跳转到一个新的路由。

Go prevPage

pop()- 回到上一页。

);

popN(n)- 回到N页之前。当N=1的时候,效果和pop()一样。

}

replace(route)- 替换当前页的路由,并立即加载新路由的视图。

});

replacePrevious(route)- 替换上一页的路由/视图。

var NavigatorDemo=React.createClass({

replacePreviousAndPop(route)- 替换上一页的路由/视图并且立刻切换回上一页。

render(){

resetTo(route)- 替换最顶级的路由并且回到它。

var rootRoute={

popToRoute(route)- 一直回到某个指定的路由。

component:FirstScene

popToTop()- 回到最顶层的路由。

};

代码:

return(

/**

initialRoute={rootRoute}                       /*  制定初始默认页面*/

* Sample React Native App

configureScene={(route)=>{

*

return Navigator.SceneConfigs.PushFromRight; /* 配置场景转场动画从右到左*/

*/'use strict';varReact = require('react-native');//增加NavigatorIOSvar{  AppRegistry,  StyleSheet,  Text,  View,  NavigatorIOS,  TouchableHighlight,} = React;/*有这样一些需求?:自定义barBarItem,例如自定义名字、图片?*//*--  启动组件 --*/varMainClass = React.createClass({  onRightButtonPress:function(){this.refs.nav.push({      title:'push view',      component: SecondScene,    });  },  render:function() {//component这里设置的是这个组件启动的时候显示的第一个子组件return();  },});/*--  首页页面组件 --*/var HomeScene = React.createClass({  render: function() {    return (push me!);  },  onPress: function() {    this.props.navigator.push({      title: 'touch View',      component: SecondScene,      passProps: { myProp: 'Axiba001' },    });  }});/*--  push后的页面组件 --*/var SecondScene = React.createClass({  render: function() {    return (push sucess!{'hi,this is prams:'+ this.props.myProp});  },});/*布局样式*/var styles = StyleSheet.create({  container: {    flex: 1,    // justifyContent: 'center',    // alignItems: 'center',    backgroundColor: '#F5FCFF',  },  home: {    paddingTop:74,  },});AppRegistry.registerComponent('AwesonProject', () => MainClass);

}}

回调函数基本相同,但是注意还有一些对导航栏的控制,例如:

renderScene={(route,navigator)=>{              /*渲染场景*/

(1 barTintColorstring

var Component=route.component;

导航条的背景颜色。

return(

(2 initialRoute{component: function, title: string, passProps: object, backButtonIcon: Image.propTypes.source, backButtonTitle: string, leftButtonIcon: Image.propTypes.source, leftButtonTitle: string, onLeftButtonPress: function, rightButtonIcon: Image.propTypes.source, rightButtonTitle: string, onRightButtonPress: function, wrapperStyle: [object Object]}

navigator={navigator}                               /*将navigator传递到下一个场景*/

NavigatorIOS使用"路由"对象来包含要渲染的子视图、它们的属性、以及导航条配置。"push"和任何其它的导航函数的参数都是这样的路由对象。

route={route}/>                                        /*将route传递到下一个场景*/

(3 itemWrapperStyleView#style

);

导航器中的组件的默认属性。一个常见的用途是设置所有页面的背景颜色。

}}

(4 navigationBarHiddenbool

/>

一个布尔值,决定导航栏是否隐藏。

);

( 5 shadowHiddenbool

}

一个布尔值,决定是否要隐藏1像素的阴影

});

( 6 tintColorstring

const styles = StyleSheet.create({

导航栏上按钮的颜色。

container: {

( 7 titleTextColorstring

flex: 1,

导航器标题的文字颜色。

justifyContent: 'center',

(8 translucentbool

alignItems: 'center',

一个布尔值,决定是否导航条是半透明的。

backgroundColor: '#F5FCFF',

相关的链接地址在这里:http://www.tuicool.com/articles/z226zin

},

btn:{

padding:5,

backgroundColor:'#06f',

borderRadius:5,

}

});

module.exports=NavigatorDemo;

本文由金沙棋牌发布于金沙棋牌官方平台,转载请注明出处:ReactNative学习实践,使用导航Navigator

关键词:

上一篇:没有了

下一篇:没有了