在app开发中,跳转页面的需求是最常见的。
Android原生跳转可以使用startActivityForResult、startActivity实现…
但是在React Native中呢?
作为得到前端青睐的React Native,使用Navigator结合路由的方式进行跳转。路由其实很好理解,就是一个url映射到具体的函数。
比如说:
# flask框架
@app.route("/login")
def login():
# 只要是/login的网址,就会跳进这个函数
// Spring
@RequestMapping("/login")
public void login() {
// 只要是/login的网址,就会跳进这个函数
}
例子太多太多了。。。其实,Android开发框架——Router、LiteRouter等等都是以路由的方式实现原生Android界面跳转。
扯远了,这里开始真正的学习React Native界面跳转。这里需要了解一个Navigator这个api了。
需要说明的是,我们需要先定义一个没有任何界面的Component,并在这个Component初始化Navigator。
// SplashComponent.js
class SplashComponent extends Component {
constructor(props) {
super(props);
}
render() {
// 这里定义第一个界面的name和对应的Component
const defaultName = "LoginComponent";
const defaultComponent = LoginComponent;
return (
<Navigator
// 初始化路由
initialRoute={{name: defaultName, component: defaultComponent}}
// 配置界面跳转的动画效果
configureScene={
(route) => {
return Navigator.SceneConfigs.FloatFromBottom;
}
}
// 跳转后,渲染界面的函数
renderScene={
(route, navigator) => {
let Component = route.component;
return <Component{...route.params} navigator={navigator}/>
}
}
/>
);
}
}
我们将定义的SplashComponent作为第一个界面。实际上,SplashComponent并没有开始任何的View显示,只是将界面跳转到了LoginComponent。
别忘了这句话
AppRegistry.registerComponent('Animation', () => SplashComponent);
接下来就是LoginComponent的编写了,这里就是一个简单的Text,点击Text后,会跳转到RegisterComponent。
// LoginComponent.js
class LoginComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<Text onPress={this.onPress.bind(this)}>点击后跳转到Register</Text>
</View>
)
}
onPress() {
const {navigator} = this.props;
navigator.push({
name: "RegisterComponent",
component: RegisterComponent,
// 传递参数,因为前面初始化Navigator的时候是使用了params,所以这里就用params
params : {
string : "login",
}
});
}
}
class RegisterComponent extends Component {
constructor(props) {
super(props);
// 这样获取参数
console.log(props.string);
}
render() {
return (
<Text onPress={() => {
const {navigator} = this.props;
// 将该界面弹出栈
navigator.pop();
}}>注册</Text>
)
}
}
上面演示了如何在两个界面中传递参数。navigator有两个重要的方法——push、pop。也就是说,本质上React Native有一个保存Scene的栈,通过管理这个栈实现界面的跳转。
但是,我们按下返回键的时候,其实并不会调用Navigator.pop()。个人推测React Native的实现会将所有的Scene都显示在一个Activity上,并不存在Activity的交互,按下返回键才不会弹出Scene。
那我们可以通过监听返回键的方式,实现弹出Scene。参数资料:https://reactnative.cn/docs/0.43/backandroid.html#content
但是,我们通过navigtor.push是相当于实现了startActivity。还没有实现startActivityForResult。
我们可以通过以下方法实现:
changeData(data) {
this.setState({
data : data
});
}
// LoginComponent.js
// 省略部分代码
onPress() {
const {navigator} = this.props;
navigator.push({
name: "RegisterComponent",
component: RegisterComponent,
params : {
string : "login",
// 将回调函数通过参数的形式传递过去
changeData : changeData
}
});
}
// RegisterComponent.js
// 省略部分代码
const {navigator} = this.props;
// 在这里调用那个函数
this.props.changeData("回调");
navigator.pop();
上述方式通过函数回调的方式解决了Navigator.pop无法传值得问题。这种方法基本解决了很多问题,但是总感觉写一个回调函数是很不妥的方式。
我们还可以通过React Native提供的DeviceEventEmitter的api实现传值。其实DeviceEventEmitter的本质实现是发布者与监听者模式。
// LoginComponent.js
// 省略部分代码
componentDidMount() {
//这里监听的事件是changeData,监听到后会自动回调changeData函数
DeviceEventEmitter.addListener('changeData', this.changData);
}
// 这里一定要移除事件的监听,避免内存泄漏
componentWillUnmount() {
this.subscription.remove();
}
// RegisterComponent.js
// 省略部分代码
// 发布事件
DeviceEventEmitter.emit('changeData',val.data);
navigator.pop();