react-native的页面跳转
引言 :react-native出来也有一段时间了,一直只是听说react-nativa是如何的好,能够实现跨平台(android、IOS).一直没有去主动交接它。直到最近,公司为了节省后期的维护成本,也同时将现有的项目进行一次升级,然后决定用react-native重新开发一套。
当然了,接触一门新的技术难免会遇到很多的难点。根据实际开发遇到的问题写点文章。巩固自己的同时也许能帮到别人。
我学习的资料网[React Native 中文网](http://reactnative.cn/)
学习前期一些属性(props)、状态(state)、样式(style)、布局(flexbox)看着敲敲代码就能比较好接受了。
难点就是卡在页面的跳转了,虽然文档也提供了页面跳转的教程,但给我的感觉是一个页面自己在跳然后修改了一写属性值。(这并不能让我很满意,于是我就决定自己找资料写一个自己满意的)
[参考地址](http://blog.youkuaiyun.com/youth_never_go_away/article/details/52572029)
正题开始:先给大家上一组图(很惭愧,不会上传视频)。
第一个界面
点击跳转的图片
点击跳转的图片
注:在android。处于主界面时,支持双击返回退出。在其他页面时,支持点击返回回到上一个界面。
在实现界面跳转时需要提前了解的知识:
- navigater(导航器)
- scene(场景)
route(路由)
这三个概念也会在下面的代码中介绍到。
代码部分
程序的入口:index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
} from 'react-native';
import SimpleComponent from './jsScene/SimpleComponent';
export default class helloRN extends Component {
render() {
return (
//显示组件
<SimpleComponent />
);
}
}
AppRegistry.registerComponent('helloRN', () => helloRN);
入口代码非常简单,就是显示一个SimpleComponent的组件(不过你们要是照着敲时,注意文件夹的关系,这个很重要)
组件SimpleComponent.js
import React, { Component } from 'react';
import { View, Text, Navigator } from 'react-native';
import FirstPageComponent from './FirstPageComponent';
export default class SimpleComponent extends Component {
render() {
//组件名字
let defaultName = 'FirstPageComponent';
//组件的Class用来实例化成<Component/>标签的
let defaultComponent = FirstPageComponent;
return (
<Navigator
//这个指定了默认的页面,也就是启动app之后会看到界面的第一屏。 需要填写两个参数: name 跟 component。
//(注意这里填什么参数纯粹是自定义的,因为这个参数也是你自己发自己收,自己在renderScene方法中处理。
// 我们这里示例用了两个参数,但其实真正使用的参数只有component)
initialRoute={{ name: defaultName, component: defaultComponent }} //初始化场景
//页面跳转动画 可以返回多个动画 使用||返回
configureScene={(route) => {
return Navigator.SceneConfigs.HorizontalSwipeJump; //设置场景的切换方式
}}
//渲染场景 route中就是我们自定义的 name 和 component
//navigator 就是Navigator对象
renderScene={(route, navigator) => {
let Component = route.component;
//Component 是route的component参数值 在路由中初始化的component的参数值是 defaultComponent
//所以 Component组件就是FirstPageComponent组件
return <Component {...route.params} navigator={navigator} />
}} />
);
}
}
这段代码里面的内容就比较复杂了,我就每个关键字逐一解释,主要的内容是return()中的内容。
< Navigater />个人Navigater是所有组件的一个容器,所有的组件都会在Navigater中进行处理,后面会有代码进行很好的解释。
initialRoute={{ name: defaultName, component: defaultComponent }},这段代码是初始化一个路由,每一个页面以route为单位在Navigater中活动(显示或移除)
return Navigator.SceneConfigs.HorizontalSwipeJump; //界面的切换效果
renderScene={(route, navigator) => {
let Component = route.component;
//Component 是route的component参数值 在路由中初始化的component的参数值是 defaultComponent
//所以 Component组件就是FirstPageComponent组件
return <Component {...route.params} navigator={navigator} />
}}
这是最重要的一段代码,渲染一个场景,然后将渲染的场景(FirstPageComponent)返回(显示出来)。
组件FirstPageComponent.js
import React, { Component } from 'react';
import {
View,
StyleSheet,
Navigator,
Text,
BackAndroid,
TouchableOpacity
} from 'react-native'
//(MyToast是本人桥接的android的Toast。实际使用的过程可以直接去掉,以免报错)
import MyToast from './MyToast';
// // 下一句中的ToastAndroid即对应上文
// // public String getName()中返回的字符串
// // 练习时请务必选择另外的名字!
//
// export default NativeModules.ToastAndroid;
import SecondPageComponent from './SecondPageComponent';
import ThirdPageComponent from './ThirdPageComponent';
import FourthPageComponent from './FourthPageComponent';
export default class FirstPageComponent extends Component{
constructor(props){
super(props);
this.state = {};
this.firstClick = 0;
this.handleBack = this.handleBack.bind(this);
}
//生命周期方法。在组建第一次绘制完成后调用,通知组建已经加载完成。
componentDidMount () {
BackAndroid.addEventListener('hardwareBackPress', this.handleBack) //增加手机物理返回键的监听
}
//生命周期方法。组建被移除时调用此方法
componentWillUnmount () {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBack) //增加手机物理返回键的监听
}
//双击返回键退出
handleBack(){
const { navigator } = this.props;
if (navigator && navigator.getCurrentRoutes().length > 1) {
navigator.pop();
return true;
}else{
let timestamp = (new Date()).valueOf();
if(timestamp - this.firstClick > 2000){
MyToast.show('在按一次退出',MyToast.SHORT);
this.firstClick = timestamp;
return true;
}else{
return false;
}
}
}
//页面的跳转
_pressButton(index){
const { navigator } = this.props;
if (navigator){
switch (index) {
case 2:
navigator.push({
name:'SecondPageComponent',
component:SecondPageComponent,
});
break;
case 3:
navigator.push({
name:'ThirdPageComponent',
component:ThirdPageComponent,
});
break;
case 4:
navigator.push({
name:'FourthPageComponent',
component:FourthPageComponent,
});
break;
default:
break;
}
}
}
render(){
return(
<View>
<TouchableOpacity onPress={this._pressButton.bind(this,2)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到2
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._pressButton.bind(this,3)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到3
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._pressButton.bind(this,4)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到4
</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
red:{
fontSize:40,
fontWeight:'300',
color:'red'
}
});
还是先从主要的方法说起
return(
<View>
<TouchableOpacity onPress={this._pressButton.bind(this,2)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到2
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._pressButton.bind(this,3)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到3
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._pressButton.bind(this,4)}
style={{ flexDirection:'row', alignItems:'center' }}>
<Text style={styles.red}>点我跳转到4
</Text>
</TouchableOpacity>
</View>
)
这只是基本的排列,主要要解释是的是this._pressButton.bind(this,4)方法。这就是点击事件调用_pressButton(index)方法,index是this后面的参数,接下来看方法
_pressButton(index){
const { navigator } = this.props;
if (navigator){
switch (index) {
case 2:
navigator.push({
name:'SecondPageComponent',
component:SecondPageComponent,
});
break;
case 3:
navigator.push({
name:'ThirdPageComponent',
component:ThirdPageComponent,
});
break;
case 4:
navigator.push({
name:'FourthPageComponent',
component:FourthPageComponent,
});
break;
default:
break;
}
}
}
在这段代码中有一个难以理解的地方就是navigater对象是哪里来的?
回到simplePageComponent.js中
return < Component {…route.params} navigator={navigator} />
在返回时返回了一个navigator对象的属性
* const { navigator } = this.props; *
这里就获取到了。
navigator.push({
name:'ThirdPageComponent',
component:ThirdPageComponent,
});
这段代码就是将ThirdPageComponent组件放入navigator的栈中。达到显示的目的。
ThirdPageComponent.js方法中就比较简单了
import React, { Component } from 'react';
import {
View,
StyleSheet,
Navigator,
Image,
Dimensions,
Text,
TouchableOpacity
} from 'react-native'
var deviceWidth = Dimensions.get('window').width;
const BANNER_IMGS = [
require('../imgs/meinv2.png'),
require('../imgs/meinv3.png'),
require('../imgs/meinv4.png'),
require('../imgs/meinv2.png')
];
export default class ThirdPageComponent extends React.Component {
constructor(props) {
super(props);
this._pressButton = this._pressButton.bind(this);
}
_pressButton() {
//获取SampleComponent中创建的Navigator对象
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
//这里对navigator进行了判断 如果navigator(导航器)对象存在的情况下 在进行操作
if (navigator) {
navigator.pop();
}
}
_renderPage(data, pageID) {
return (
<Image
source={data}
style={styles.page}/>
);
}
//创建点击区域 当点击的时候 进行 页面的跳转 也就是对navigator的参数进行设置 使其跳转到 第二个界面
render() {
return (
<View >
<TouchableOpacity onPress={this._pressButton.bind(this)}
style={{flexDirection:'row' ,alignItems: 'center'}}>
<Text style={styles.red}>点我跳回去</Text>
</TouchableOpacity>
<Text style={styles.red}>我是第三页面</Text>
</View>
);
}
}
const styles=StyleSheet.create({
red:{
fontSize:40,
fontWeight:'bold',
color:'red'
},
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'flex-start',
paddingTop:5,
paddingLeft:5,
backgroundColor:'#999999',
paddingRight:5,
paddingBottom:5,
},
page: {
width: deviceWidth,//设备宽(只是一种实现,此处多余)
flex: 1,
height: 130,
resizeMode: 'stretch'
},
});
这个组件中只有一个重要代码
navigator.pop(); //返回上一个组件
恩!到此为止,一个react-native的原生的页面的跳转就完成,还加入一些返回的细节。(MyToast是桥接的android的Toast。实际使用的过程可以直接去掉,以免报错)