前言
我司在weex上的应用是保证三端统一,为了延续web开发体验,统一在三端的跳转都采用url的形式,即采用<a>组件,或者自定义的openUrl方法进行跳转。
假如现在点击B按钮
跳转到/b.html
页面,在vue文件中统一书写openUrl('/b.html')
。H5中就是简单的调用window.location.href = /b.html
,在native中会打开一个视图,然后去下载跟/b.html
对应的b.min.js
js文件,进行原生视图渲染。页面与js文件的映射关系以及如何维护可以翻阅之前的文章查看App的跳转规则的weex支持方案设计。
统一采用url跳转的方式进行页面跳转,为了传参方便,我们也统一采用在url后拼接参数的形式进行页面间传参。
正向传参
不管是weex(native)还是weex(H5)都是通过页面的url进行跳转。
假设案例:
x.com/a.html
跳转到x.com/b.html?age=12
。
1)weex(native) > weex(native) 实例化时从url中取得参数并传入到实例中
每个 Weex 页面都有被创建、被销毁两个必经阶段,同时在 Weex 页面运行过程中,native 有机会主动向 Weex 页面发送消息。
Native 有机会在创建一个 Weex 页面的时候,传入一份外部数据,JS 框架也有机会借此机会为相同的 JS bundle 配合不同的 data 生成不同的页面内容。
由上可知native在渲染一个weex页面的时候有机会往这个weex页面传入一个Object类型的数据,数据能通过weex.config
取得。
在我司的设计中,native首先会截取跳转的url,然后截取下参数,再把参数传入到weex实例中去。这样我们就能通过weex.config.age
进行数据的获取,从而渲染不同的页面内容。
[_instance renderWithURL:[NSURL URLWithString:mstrURL] options:[self SHWeexOptionsWithH5URL:mstrH5URL withURL:mstrURL] data:nil];
2)weex(web)> weex(web)在weex-vue-render层面从url读取参数,写入weex.config
native实现这上述讲到的方式进行数据传递,那么web端也要以相同的方式weex.config.age
这种方式去取得页面中的参数age。
本司web端的weex依赖文件是通过webpack打包的方式,所以在requireweex-vue-render
依赖后,获取当前url的参数,再存进weex.config
对象就好了。
require('weex-vue-render')
// hack 将页面url的参数写入到weex.config中
// app已经有这样的方法,h5自己实现
let urlParamObj = {};
try {
urlParamObj = utils.parseUrl(window.location.search.slice(1), '&', "=", {maxKeys: 0});
} catch (error) {
console.log('--------------weex.js parseUrl---------------------');
console.log(error);
console.log('------------------------------------');
}
for (let key in urlParamObj) {
window.weex.config[key] = encodeURIComponent(urlParamObj[key]);
}
3)native > weex(native) 同理
4)native > weex(web) 同理
对于3、4两种情况,native跳转weex,不管是跳到weex(native)还是跳转到weex(web),都是使用url的形式进行跳转。例:x.com/b.html?age=12
。上面也讲到了在weex页面native和web如如何将参数写入weex.config对象中去的。要取得参数,统一在vue中编写weex.config.age
便能取得传递进来的age参数。
至此我们统一了三端(ios、android、H5)从A页面到B页面正向的传参方式。
反向传参
1)weexA(native) > weexB(native),weexB页面选择完毕返回weexA页面, weexB(native) > weexA(native)
在提交订单页面我们可以选择优惠券,进入到优惠券使用页面,首先会进行正向传参,因为选择优惠券页面会使用提交订单页的订单数据。
然后在选择优惠券页面选择任意优惠券会回到提交订单页,这时需要携带优惠券数据回去,我们称这个为反向传参。
查看官网我们本可以使用BroadcastChannel这个api去做实例间的数据传递,但是在vue的JS Framework中还不支持这个特性,所以我们暂时使用的是globalEvent这个实例级别的api去代替应用级别的数据传递。
我们首先在公司内部集成的module中增加了fireGlobalEvent
方法,在选择优惠券页面调用这个方法。
fireGlobalEvent('getConpon', {
id: '3323',
}, function () {
if (web) {
} else {
navigator.pop()
}
})
这个方法首先注册了getCoupon
事件,然后传递了数据对象
{
id: '3323'
}
最后注册了一个回调,当前页面会执行这个回调,回退上一页。
而在上一页(提交订单页),注册了一个事件监听,当这个事件名被触发了,就接收来自这个事件的数据。
const globalEvent = weex.requireModule('globalEvent');
globalEvent.addEventListener('getCoupon', function (e) {
console.log("get getCoupon")
});
这是业务逻辑中的实现,我们再来看看native为了达到返回上一页并传参效果做了什么处理(android为例)。
public void fireGlobalEvent(String name, String data, final JSCallback callback) {
SHStorageManager.putToCache(SHWeexConstants.WEEX, SHWeexConstants.NAME, name);
SHStorageManager.putToCache(SHWeexConstants.WEEX, SHWeexConstants.DATA, data);
if (null != callback) {
callback.invoke(new JSONObject());
}
}
当在业务中调用fireGlobalEvent
方法时,native会把传入的事件名和data存入缓存。然后执行业务中定义的回调函数,而回调中会有navigator.pop()
方法,意味着退出当前weex实例进入到上一个页面。
public void onResume() {
if (wxInstance != null) {
wxInstance.onActivityResume();
String data = SHStorageManager.get(SHWeexConstants.WEEX, SHWeexConstants.DATA, "");
if (!TextUtils.isEmpty(data)) {
String name = SHStorageManager.get(SHWeexConstants.WEEX, SHWeexConstants.NAME, "");
try {
JSONObject jsonObj = JSONObject.parseObject(data);
Map<String, Object> params = new HashMap<>();
for (Map.Entry<String, Object> entry : jsonObj.entrySet()) {
params.put(entry.getKey(), entry.getValue());
}
wxInstance.fireGlobalEventCallback(name, params);
} catch (Exception e) {
SHWeexLog.e(e);
} finally {
SHStorageManager.removeFromCache(SHWeexConstants.WEEX, SHWeexConstants.DATA);
SHStorageManager.removeFromCache(SHWeexConstants.WEEX, SHWeexConstants.NAME);
}
}
}
}
然后native会在上一个页面出现时,去缓存中取得之前存入的数据和事件名,再调用官方提供的实例apifireGlobalEventCallback,调用对应的事件,并传数据。
当native中执行了fireGlobalEventCallback
这个方法,上一页的事件监听函数就会取得数据。
至此就完成了native中数据的反向传递。
2)weexA(web) > weexB(web), weexB(web) > weexA(web)
反向传递参数在weex的web端就更加好处理了,AB页面都是通过连接后面拼接参数的形式进行传递参数,那么反向传参跟正向传参还是可以按照之前的逻辑进行。
在设计api时特意在回调中会对是否web环境做了判断,因为H5和native在反向传参的行为完全不同,所以判断逻辑会在业务中进行,更方便大家在写业务时进行不同情况不同处理。
fireGlobalEvent('getConpon', {
id: '3323',
}, function () {
if (web) {
openUrl('/a.html?id=' + '3323');
} else {
navigator.pop();
}
})