Router - Ext Plugin #

介绍 #

Router 作为 Ext 的内置插件,为其提供更加强大好用的路由功能。

Router 具有如下特点:

  1. 封装 Native 提供的原生路由跳转,提供更加友好的接口。

  2. view 耦合,无需手动配置路由映射关系。

  3. 强大、自由的导航栏配置。

  4. 传参、动画等拓展功能。

  5. 简洁直观的生命周期。

  6. 可以在含有 native 页面的混合应用中灵活地跳转。

开始 #

引用与配置:


// 配置业务 hybridId,在多业务跳转时会用到
Ext.defaults.hybridId = 'hotel';
// 配置首页(可以不配置,默认为 require 的第一个页面)
Ext.defaults.indexView = 'base';

// 引入页面
require('./views/base');
require('./views/pageA');
require('./views/pageB');

注意:

  • Router 会自动根据配置去调 AppRegistry.registerComponent() 方法。

API #

open(name[, opts])

打开一个新的页面(新建历史)。

  • name String 目标页面的名字

  • opts Object 配置项

    • opts.param Object 需要传递的参数

    • opts.sceneConfigs Object|String 场景配置项或预设动画名,打开页面的退场动画由入场动画决定

      • 选择了 moveFromTop 后只能从右进从右出,不能以其他方向退场
      • ios 与 adr 表现分别跟随大客户端效果实现
可选动画类别 效果
moveFromTop 上进上出
moveFromRight 右进右出(默认值)
moveFromLeft 左进左出
moveFromBottom 下进下出
Fade 淡入淡出
NoAnimation 无动画

back([opts])

回到上一个页面。

  • opts Object 配置项

    • opts.param Object 需要传递的参数

backTo(name[, opts])

回到指定页面。

  • name String 目标页面的名字

  • opts Object 配置项

    • opts.param Object 需要传递的参数

goto(name[, opts])

前往指定页面(历史中有则回退,没有则新建历史)。

  • name String 目标页面的名字

  • opts Object 配置项

    • opts.param Object 需要传递的参数

    • opts.sceneConfigs Object|String 场景配置项或预设动画名(如果是返回动作,此配置项无效)

home([opts])

回到首页。

  • opts Object 配置项

    • opts.param Object 需要传递的参数

close(name)

关闭指定页面。默认关闭当前页,返回上一页。

  • name String 目标页面的名字

exit([opts])

  • opts Object 配置项

    • opts.param Object 需要传递的参数

退出当前 RN 项目。

生命周期 #

以下所有注册回调函数内部 this 均为当前页面。

ready()

页面准备完成时。通过 this.porps.param 可以获取 open(name, opts) 时传入的参数。

举例:从 A 页面打开 B 页面,此时 B 页面就准备完成了。

actived(param)

页面激活时。param 为来源页携带的参数。

举例:B 页面是从 A 页面打开的,现在从 B 页面返回 A 页面,此时 A 页面就被激活了。

deactived()

页面失活时。

举例:从 A 页面打开 B 页面,此时 A 页面就失活了。

destroy()

页面销毁时。

举例:B 页面是从 A 页面打开的,现在从 B 页面返回 A 页面,此时 B 页面就被销毁了。

API 和生命周期的关系 #

API 触发的生命周期回调
open 当前页面的 deactive 和下一页面的 readyactived
goto 若新建历史:当前页面的 deactive 和下一页面的 readyactived;若回到历史:当前页面的 deactivedestroy 和下一页面的 actived
back 当前页面的 deactivedestroy 和下一页面的 actived
backTo 当前页面的 deactivedestroy 和下一页面的 actived
home 当前页面的 deactivedestroy 和下一页面的 actived
close 若关闭当前页面:当前页面的 deactivedestroy 和下一页面的 actived

导航栏 #

Router 默认提供了接近 iOS 原生样式的导航栏(类似 NavigatorIOS)。可以通过配置 Ext.defaults.navBar.isShow = true 来使用。

全局配置 #

// 配置全局导航栏
Ext.defaults.navBar = {
    // 是否显示,默认为 false,不显示
    isShow: true,
    // 背景色,默认 Qunar 蓝
    backgroundColor: 'red',
    // 导航栏文字颜色,默认白色
    color: 'black',
    // 导航栏高度,默认44(不包括状态栏高度)
    height: 80,
    //左右按钮宽度,默认60
    buttonWidth:60,
    //状态栏背景色,默认透明
    statusBarBackgroundColor:'transparent',
    // 导航栏按钮点击不透明度,默认 0.6
    activeOpacity: 0.8,
    // 左侧按钮文字,默认'返回'
    leftButtonText: '<back'
};

页面级配置 #

页面的routerPlugin可以覆盖全局配置的任意一项,并且新增了标题、导航栏左右按键和页面样式的相关配置。

class base extends QView {
    // 配置页面导航栏
    static routerPlugin = {
        // 是否显示导航栏
        isShow: true,
        // 背景色,默认 Qunar 蓝
        backgroundColor: 'red',
        // 文本颜色,默认白色
        color: 'black',
        // 按钮宽度
        buttonWidth:60,
        // 状态栏背景色
        statusBarBackgroundColor:'red',
        // 导航栏高度
        height:80,
        //activeOpacity
        activeOpacity:0.6
        // 标题,默认route.name
        // 支持传入多种参数:
        // 字符串;
        // 返回JSX的函数,接受store作为参数:
        // (store)=>(<TouchableOpacity onPress={()=>alert('custom jsx')}>
        //    <Text>test</Text>
        // </TouchableOpacity>)
        // JSX
        title: 'Base',
        // 左侧按钮,默认为字符串'返回'
        // 同样支持传入字符串/函数/JSX
        leftButtonText: <Text>返回</Text>,
        // 左侧按钮点击事件,默认 `Ext.back()`
        // 接受一个参数store
        leftButtonPressEvent(store) {
            alert('left...')
        },
        // 右侧按钮文字,默认空字符串
        // 同样支持传入字符串/函数/JSX
        rightButtonText(store){
          return (
            <Text>test</Text>
          );
        },
        // 右侧按钮点击事件,默认空函数
        rightButtonPressEvent(store) {
            alert('right...');
        }
    };
}

标题设置 #

setTitle(title)

设置当前页面导航栏的标题。

  • title String/Function/JSX 使用方式与配置里面的title完全一致

举例:

//传入字符串
Ext.Router.setTitle('new Title');
//传入JSX
Ext.Router.setTitle(
  <Text>new Title</Text>
);
//传入返回JSX的函数
Ext.Router.setTitle((store)=>(
  <Text>Test</Text>
));

open(viewName, {title})

打开新页面并设置新页面的标题。

  • title String 标题

举例:

Ext.open('pageA', {
    title: 'new Title',
});

#

Router 封装了 QRN 提供的 Native 桥,Router 自身处理了大部分桥,用户用到只会有以下几种:

广播 #

发送广播 #

Ext.Router.Bridge.sendBroadcast({
    // 广播名
    name: 'getSomeMsg',
    // 广播内容
    data: {
        msg: 'i tell u a msg'
    },
    // 指定发送目标,不指定则发给全局
    hybridId: 'hotel',
});

接收广播 #

DeviceEventEmitter.addListener('getSomeMsg', (data) => {
    // 以上面发送广播的 data 为例,接收到的 data 会长这样:
    data = {
        msg: 'i tell u a msg'
    };
});

发送 scheme #

Ext.Router.Bridge.sendScheme({
    // 地址
    url: '',
    // 安卓透明层标识(只有安卓才有)
    adrToken: '',
    // 数据
    data: {
        //类似iOS的popThenPush效果,由于底层机制不同,此标识仅对Adr生效
        adrPopThenPush: true,
    },
}, (res) => {
    // 发送后的回调
    res = {
        // 是否成功
        ret: true,
        // 数据
        data: {},
    };
});

挂载在 Ext 上的对象

Router 会通过 Ext.Router 暴露出来。除了所有的 API 外,还暴露了内部的页面容器 Ext.Router._views

实战 #

Native 页面跳转 #

Router 极大便利了 RN 页面和 Native 页面(包括 HY 页面)的互跳操作。

在阅读下面内容前强烈建议先了解下与 RN 相关环境下的 Scheme:传送门

Native -> RN #

Native 打开 RN 页面一般有两种方式:

1. 原生方法 #

通过 native 代码打开,例如 iOS 通过 QRCTVCCreater 方法,详情参考 iOSAndroid

如果首页需要获取从 Native 传入的参数,需要通过 initialProperties.param 携带。

2. 发送 Scheme #

通过发送 Scheme 也能跳转到 RN 页面,以 iOS 为例:

@interface JumpHandle : NSObject
/**
 *  通过URL和urlData来调用界面
 *
 *  @param url          跳转到的URL,通常为 qunariphone://hotel/xxx 的形式
 *  @param urldata      处理URL所需使用的数据
 *  @param responseDelg 回调对象
 *  @param userInfo     自定义对象
 *
 *  @return 返回是否有模块接受该URL并进行处理,处理URL可能是异步的,不能保证线程安全
 */
+ (BOOL)jumpHandleOpenURL:(NSURL *)url
              withUrlData:(NSDictionary *)urldata
             responseDelg:(id<JumpHandleResponsePrt>)responseDelg
                 userInfo:(id)userInfo;
@end

RN -> Native #

一般通过发 Scheme 方式,举例:

Ext.Router.Bridge.sendScheme({
    url: 'qunariphone://react/debug',
});

以上可以打开一个 native 页面。

HY -> RN #

通过 a 标签进行跳转,举例:

<p>
    <a href="qunariphone://react/open?hybridId=qunar_react_native_ext&pageName=pageA">open:强制新开</a>
</p>
<p>
    <a href="qunariphone://react/biz?hybridId=qunar_react_native_ext&pageName=pageA&forceOpen=true&initProps=%7B%22param%22%3A%7B%22name%22%3A%22wyy%22%7D%7D">biz:强制新开</a>
</p>
<p>
    <a href="qunariphone://react/biz?hybridId=qunar_react_native_ext&pageName=base&initProps=%7B%22param%22%3A%7B%22name%22%3A%22wyy%22%7D%7D">biz:返回 base</a>
</p>
<p>
    <a href="qunariphone://react/biz?hybridId=qunar_react_native_ext&pageName=pageA&initProps=%7B%22param%22%3A%7B%22name%22%3A%22wyy%22%7D%7D">biz:返回 pageA</a>
</p>

具体可以参考 QRN 配套测试 HY Demo

RN -> HY #

通过调用 Ext.Router.Bridge.sendScheme 方法,举例:

let url = 'qunariphone://hy?url=http%3A%2F%2Fwyy.qunar.com%2Fqreact-test-hy%2Findex.html&loadview=auto';
Ext.Router.Bridge.sendScheme({
    url,
});

其它功能 #

阻止安卓物理返回 #

组件支持 onBackPressed 方法,方法返回 true 表示关闭安卓物理返回的响应,false 表示恢复安卓物理返回的响应。

class SceneAndroidBack extends QView {
    //...
    onBackPressed() {
        return true;
    }
}

修改手势回退开启状态 #

调用 Ext.setSwipeBackEnabled 方法可以设置App的手势回退是否开启。

Ext.setSwipeBackEnabled(true); //开启手势回退,false为关闭

设置别名 #

组件默认添加 setView(name) 方法,针对已经打开的页面设置别名,方法返回 true 表示设置成功,false 表示设置失败。

class SetView extends QView {
    render() {
        return (
            <TouchableOpacity onPress={() => this.setView('xxx')}>
                <Text>设置别名</Text>
            </TouchableOpacity>
        )
    }
}