Weex超多大坑,最好别用
白菜普及
Weex 基于当代先进的 Web 开发技术,使用同一套代码来构建 Android、iOS 和 Web 应用。
Weex 的结构是解耦的,渲染引擎与语法层是分开的,也不依赖任何特定的前端框架,目前主要支持 Vue.js 和 Rax 这两个前端框架。Weex 的另一个主要目标是跟进当代先进的 Web 开发和原生开发的技术,使生产力和性能共存。在开发 Weex 页面就像开发普通网页一样;在渲染 Weex 页面时和渲染原生页面一样。
Weex与Native页面之间的通信主要是用module和globalEvent来实现,其中globalEvent可以为通过vue交互来与weex进行通信
一. globalEvent:
globalEvent 用于监听持久性事件,全局事件是需要额外 APIs 处理的次要 API。通过 addEventListener 注册事件监听,当你不再需要的时候,也可以通过 removeEventListener 取消事件监听。
Native端
let testDic = ["key" : "native主动发起广播至weex"]
weexInstance.fireGlobalEvent("NativeGlobalEvent", params: testDic)
Vue.js
const globalEvent = weex.requireModule('globalEvent')
export default {
methods: {
......省略N多代码
addGlobalObserver() {
globalEvent.addEventListener("NativeGlobalEvent", function (e) {
modal.alert({
message: e.key,
});
})
},
removeGlobalObserver() {
globalEvent.removeEventListener("NativeGlobalEvent")
}
}
}
坑:多次调用addEventListener方法后,无法覆盖回调(函数),会触发多次回调的执行。
exp: Vue.js多次调用addEventListener方法(比如5次),当Native的Weex实例发起fireGlobalEvent时,会直接执行5次函数体的 内的代码块;再此基础上手动调用3次,在native端再进行一次fireGlobalEvent操作,则会累积执行8次函数体内的代码块!但是如果调用removeEventListener,则会把这“八份回调”全部清除。
所以实现通知时候需要额外处理相关的代码逻辑
二.注册Module和callback回调
Native端
- 创建一个遵循WXModuleProtocol协议的 NSObject 类,并通过宏WX_EXPORT_METHOD将类中定义的方法暴露给Weex,而在native中执行完操作后,可以在设计接口处添加回调,通过block与对应Weex页面进行通信(比如传必要的参数给Weex页面),其中回调block有两种,WXModuleCallback 和 WXModuleKeepAliveCallback
void (^WXModuleCallback)(id result):回调仅执行一次后释放
void (^WXModuleKeepAliveCallback)(id result, BOOL keepAlive):回调一直存在,根据keepAlive的值来决定回调是仅执行一次还是一直保留。注意:回传的result数据可以是任意类型(NSDictionary, NSString, NSArray, Int, Float, Bool),因此要提前与编写Vue的童鞋约定好对应的格式
- (void)showInfoFromWeexKeepAlive:(nullable NSDictionary *)infos keepAliveCallback:(nullable WXModuleKeepAliveCallback)callback {
UIAlertController *alert = [[UIAlertController alloc] init];
alert.title = @"Native Alert";
alert.message = infos[@"message"];
UIAlertAction *action0 = [UIAlertAction actionWithTitle:@"got it" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
callback(@{@"backInfo":@"confirm btn click"},true);
}];
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"cancle" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
callback(@{@"backInfo":@"cancle btn click"},false);
}];
[alert addAction:action0];
[alert addAction:action1];
[UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
<!- 模拟block keepAlive场景 ->
callback(@{@"backInfo":@"this is the first callback and keep block alive"},true);
}
- 然后在Appdelegate方法中初始化完Weex环境后,通过调用 WXSDKEngine 中的 registerModule:withClass方法来注册自己的Module,以便Weex能够识别并使用Native定义的Module
WXSDKEngine.initSDKEnvironment()
WXSDKEngine.registerModule("YFTest", with: TestWXModule.classForCoder())
vue.js端
- 通过requireModule引入native定义的module,且需同名
- 调用module中开放的API执行相关操作
const nativeEvent = weex.requireModule('YFTest')
export default {
methods: {
......省略N多代码
sendParamToNativeKeepAlive(event) {
nativeEvent.showInfoFromWeexKeepAlive({"message":"show message from weex"}, function(ret) {
var str = "";
str = ret.backInfo;
modal.confirm({
message: "weex alert\n" + str,
okTitle: 'i know'
})
});
}
}
};
坑:回调函数可能释放也可能一直存在,需要对不同的应用场景进行区分
三、在写vue.js页面的发现在native上很多CSS的样式不支持
- 简写均不支持,如:margin: 15px 15px 30px 30px;
- 百分比不支持,如:width: 80%
- 不能使用嵌套的CSS,布局上只支持flex
- native上不存在全局样式,使用了预处理器也是不行(查了资料,web是可以有全局样式)
- ue.js页面使用内置modal模块的toast时,无法屏蔽多次点击操作,需要特殊处理
- weexView无法使用自动布局,渲染完成的weex页面的frame与weexInstance的frame保持一致
四、页面之间的跳转
- native -> weex:weex页面需要一个控制器作为容器, 此时就是native间的跳转
- weex -> weex: 使用weex内置的navigator模块,weex之间传递数据需要用内置模块storage
- weex -> native: 需要通过module形式通过发送事件到native来实现跳转(参照module的使用)
附:降级方案参考文章
饿了么
飞猪
根据接口配置,接口同时给native提供js文件和h5链接
- 由后台决定Native使用何种方式加载(Weex | Web)
- 如果后台指定使用weex,如果渲染失败(包括降级和其他一些会导致渲染失败的原因)则直接移除用来渲染weex页面的view,并改用webView来实现
坑:如果使用webView来实现,页面之间的通信也就变成了hybrid方式,而不是前面讨论的weex-native之间的module方式
weexInstance.onFailed = { [weak self] (view) in
//渲染出错,包括降级,需要在这里切换至web展示
}
网友评论