Weex超多大坑,最好別用
白菜普及
Weex 基于當(dāng)代先進(jìn)的 Web 開發(fā)技術(shù),使用同一套代碼來構(gòu)建 Android竹揍、iOS 和 Web 應(yīng)用材失。
Weex 的結(jié)構(gòu)是解耦的痕鳍,渲染引擎與語法層是分開的,也不依賴任何特定的前端框架龙巨,目前主要支持 Vue.js 和 Rax 這兩個前端框架笼呆。Weex 的另一個主要目標(biāo)是跟進(jìn)當(dāng)代先進(jìn)的 Web 開發(fā)和原生開發(fā)的技術(shù),使生產(chǎn)力和性能共存旨别。在開發(fā) Weex 頁面就像開發(fā)普通網(wǎng)頁一樣诗赌;在渲染 Weex 頁面時和渲染原生頁面一樣。
Weex與Native頁面之間的通信主要是用module和globalEvent來實(shí)現(xiàn)秸弛,其中g(shù)lobalEvent可以為通過vue交互來與weex進(jìn)行通信
一. globalEvent:
globalEvent 用于監(jiān)聽持久性事件铭若,全局事件是需要額外 APIs 處理的次要 API洪碳。通過 addEventListener 注冊事件監(jiān)聽,當(dāng)你不再需要的時候奥喻,也可以通過 removeEventListener 取消事件監(jiān)聽偶宫。
Native端
let testDic = ["key" : "native主動發(fā)起廣播至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")
}
}
}
坑:多次調(diào)用addEventListener方法后,無法覆蓋回調(diào)(函數(shù))环鲤,會觸發(fā)多次回調(diào)的執(zhí)行纯趋。
exp: Vue.js多次調(diào)用addEventListener方法(比如5次),當(dāng)Native的Weex實(shí)例發(fā)起fireGlobalEvent時冷离,會直接執(zhí)行5次函數(shù)體的 內(nèi)的代碼塊吵冒;再此基礎(chǔ)上手動調(diào)用3次,在native端再進(jìn)行一次fireGlobalEvent操作西剥,則會累積執(zhí)行8次函數(shù)體內(nèi)的代碼塊痹栖!但是如果調(diào)用removeEventListener,則會把這“八份回調(diào)”全部清除瞭空。
所以實(shí)現(xiàn)通知時候需要額外處理相關(guān)的代碼邏輯
二.注冊Module和callback回調(diào)
Native端
- 創(chuàng)建一個遵循WXModuleProtocol協(xié)議的 NSObject 類揪阿,并通過宏WX_EXPORT_METHOD將類中定義的方法暴露給Weex,而在native中執(zhí)行完操作后咆畏,可以在設(shè)計接口處添加回調(diào)南捂,通過block與對應(yīng)Weex頁面進(jìn)行通信(比如傳必要的參數(shù)給Weex頁面),其中回調(diào)block有兩種旧找,WXModuleCallback 和 WXModuleKeepAliveCallback
void (^WXModuleCallback)(id result):回調(diào)僅執(zhí)行一次后釋放
void (^WXModuleKeepAliveCallback)(id result, BOOL keepAlive):回調(diào)一直存在溺健,根據(jù)keepAlive的值來決定回調(diào)是僅執(zhí)行一次還是一直保留。注意:回傳的result數(shù)據(jù)可以是任意類型(NSDictionary, NSString, NSArray, Int, Float, Bool)钮蛛,因此要提前與編寫Vue的童鞋約定好對應(yīng)的格式
- (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環(huán)境后鞭缭,通過調(diào)用 WXSDKEngine 中的 registerModule:withClass方法來注冊自己的Module,以便Weex能夠識別并使用Native定義的Module
WXSDKEngine.initSDKEnvironment()
WXSDKEngine.registerModule("YFTest", with: TestWXModule.classForCoder())
vue.js端
- 通過requireModule引入native定義的module魏颓,且需同名
- 調(diào)用module中開放的API執(zhí)行相關(guān)操作
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'
})
});
}
}
};
坑:回調(diào)函數(shù)可能釋放也可能一直存在岭辣,需要對不同的應(yīng)用場景進(jìn)行區(qū)分
三、在寫vue.js頁面的發(fā)現(xiàn)在native上很多CSS的樣式不支持
- 簡寫均不支持甸饱,如:margin: 15px 15px 30px 30px;
- 百分比不支持易结,如:width: 80%
- 不能使用嵌套的CSS,布局上只支持flex
- native上不存在全局樣式柜候,使用了預(yù)處理器也是不行(查了資料,web是可以有全局樣式)
- ue.js頁面使用內(nèi)置modal模塊的toast時躏精,無法屏蔽多次點(diǎn)擊操作渣刷,需要特殊處理
- weexView無法使用自動布局,渲染完成的weex頁面的frame與weexInstance的frame保持一致
四矗烛、頁面之間的跳轉(zhuǎn)
- native -> weex:weex頁面需要一個控制器作為容器, 此時就是native間的跳轉(zhuǎn)
- weex -> weex: 使用weex內(nèi)置的navigator模塊辅柴,weex之間傳遞數(shù)據(jù)需要用內(nèi)置模塊storage
- weex -> native: 需要通過module形式通過發(fā)送事件到native來實(shí)現(xiàn)跳轉(zhuǎn)(參照module的使用)
附:降級方案參考文章
餓了么
飛豬
根據(jù)接口配置箩溃,接口同時給native提供js文件和h5鏈接
- 由后臺決定Native使用何種方式加載(Weex | Web)
- 如果后臺指定使用weex,如果渲染失斅掂帧(包括降級和其他一些會導(dǎo)致渲染失敗的原因)則直接移除用來渲染weex頁面的view涣旨,并改用webView來實(shí)現(xiàn)
坑:如果使用webView來實(shí)現(xiàn),頁面之間的通信也就變成了hybrid方式股冗,而不是前面討論的weex-native之間的module方式
weexInstance.onFailed = { [weak self] (view) in
//渲染出錯霹陡,包括降級,需要在這里切換至web展示
}