react-native之Navigator组件详解

Navigator算得上是react-native的核心组件之一,通过它基本上可以解决SPA里的历史管理功能,并且还自带跳转动画和后退手势,通过头部来控制页面跳转的APP基本上都要用到Navigator组件。Navigator的具体API官网都有,这里不做介绍。

本文主要说一些我使用中遇到的问题和其解决方案,包括如何管理整个router,如何自定义每个页面的头部左右按钮和一些自定义头部的样式,以及如何使Navigator可以和页面之间进行数据交互。

我们的APP整个是用Navigator来管理router,所以在入口文件中就直接配置Navigator,看index.ios.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
render() {
return (
<Navigator
initialRoute={{name: 'home'}}
renderScene={this.RouteMapper.bind(this)}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}}
/>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const HomeView = require('./App/views/home');
const LoginView = require('./App/views/login');
RouteMapper(route, navigationOperations, onComponentRef) {
let _navigator = navigationOperations;
switch(route.name){
case 'home':
return (
<HomeView userToken={route.userToken} navigator={_navigator} />
);
break;
case 'login':
return (
<LoginView navigator={_navigator} />
);
break;
}
}

这里的代码很容易看懂,initialRoute属性传入初始化的页面name,所有的页面配置在RouteMapper中,并且定义一些页面之间需要传递的数据比如userToken或者是详情页的ID。主要的是在子页面中的render配置。我们可以看下HomeView:

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
constructor(props) {
super(props);
this.state = {
message_count:0
};
let self = this;
this.NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
return (
<TouchableOpacity
onPress={() => navigator.parentNavigator.pop()}
style={styles.leftIcon}>
<Image
style={styles.backIcon}
source={require('../img/icon_back.png')}
/>
</TouchableOpacity>
);
},
RightButton(route, navigator, index, navState) {
return (
<TouchableOpacity
onPress={() => navigator.parentNavigator.push({
name: 'mymessage',
userToken:self.thisToken
})}
style={styles.leftIcon}>
<Image
style={styles.messageIcon}
source={require('../img/icon_messageheader.png')}
/>
{self.setMessageTips()}
</TouchableOpacity>
);
},
Title(route, navigator, index, navState) {
return null;
}
}
}
setMessageTips (){
const {message_count} = this.state;
if(message_count){
return (
<Text style={styles.messageTips}>{message_count}</Text>
)
}
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={styles.navBar}
routeMapper={this.NavigationBarRouteMapper} />
}
/>
);
}
renderScene(route, navigator) {
return (
<View style={styles.container}>
body
</View>
);
}

所有页面的配置基本上类似,在子页面的render里再返回一个Navigator组件,它的renderScene来返回这个页面的实际body,它的navigationBar在子页面中重新定义,我是定义在constructor中,这样我们就可以完全控制每个页面的头部样式。并且可以进行子页面组件内的数据交互。