?本篇將節(jié)操滿滿的安利Weex(? ̄? ??  ̄??),不一樣的角度推薦你入坑,官網(wǎng)有的我們不拖泥,這里將給你補(bǔ)充官方?jīng)]有的,深入到蹲坑給你排憂解難,總會(huì)給你點(diǎn)驚喜,內(nèi)容越后越干,請(qǐng)緊張的往下看。

***** 本文配套,超完整 Weex 項(xiàng)目推薦 : GSYGithubAppWeex *****
一、簡介
?有對(duì)比才有傷害,說到Weex,難免讓人聯(lián)系React Native。雖同為跨平臺(tái)移動(dòng)端解決方案,擁JavaScript妄一統(tǒng)天下,單兩者的設(shè)計(jì)理念其實(shí)截然不同。
?這里先介紹下兩者的差異,給徘徊在 React Native 和 Weex 之間的人,理解更適合哪些場景。
| 類型 | React Native | Weex |
|---|---|---|
| 性能 | 較好 | 較弱 |
| 上手難度 | 稍高 | 容易 |
| 核心理念 | React | Vue |
| 框架程度 | 較重 | 較輕 |
| 特點(diǎn) | 適合開發(fā)整體App | 適合單頁面 |
| 社區(qū) | 豐富,F(xiàn)acebook維護(hù) | 略殘念,目前托管apache |
| 支持 | Android、IOS | Android、IOS、Web |
| 適應(yīng)性 | 原生開學(xué)習(xí)成本低 | Web開發(fā)學(xué)習(xí)成本低 |
| JS引擎 | JSCore | V8 |
?作為兩個(gè)框架的深度體驗(yàn)者,個(gè)人總結(jié)出上面的對(duì)比,其中可以看出:
React Native更適合開發(fā)完整的App,因?yàn)樗男阅茌^好,第三方插件豐富,社群活躍并且維護(hù)較好,文檔完整等(本篇主角是Weex好吧魂淡(#?Д?))。
Weex更適合開發(fā)單頁面集成,這也是阿里的業(yè)務(wù)特性。
當(dāng)然Weex也可以開發(fā)完整的多頁面App,同時(shí)我也是這么用過,不過效果對(duì)比React Native,顯然強(qiáng)差人意。Weex勝在容易上手,基于Vue的設(shè)計(jì)模式,類MVVM的實(shí)現(xiàn),也讓前端能更無縫的實(shí)現(xiàn)一些高性能的App業(yè)務(wù)。
Weex兼容Android、IOS、Web三端,在單頁面的實(shí)現(xiàn)上,它有著React Native無法睥睨的先天優(yōu)勢。
Weex的社群,個(gè)人覺得還是弱,資料不足,文檔簡單,第三方支持太弱。和React Native一樣支持帶原生功能的插件開發(fā),但是,支持太少了,這也提高了后期的開發(fā)門檻。同時(shí),一個(gè)小問題很容易讓入初學(xué)者,三過門而不入,作為一個(gè)發(fā)布了兩年的框架,還是比較讓人吐槽的。

二、原理
?這里簡要說明下Weex在android下的分層以及原理。
?Weex主要包括三大部分:JS Bridge、Render、Dom,分別對(duì)應(yīng)WXBridgeManager、WXRenderManager、WXDomManager 。通過WXSDKManager統(tǒng)一管理。其中JS Bridge和Dom運(yùn)行在獨(dú)立的HandlerThread中,而Render運(yùn)行在UI線程。JS Bridge主要用來和 JS 端實(shí)現(xiàn)進(jìn)行雙向通信,比如把js端的dom結(jié)構(gòu)傳遞給Dom線程。Dom主要是用于負(fù)責(zé)dom的解析、映射、添加等等的操作,最后通知UI線程更新。而Render負(fù)責(zé)在UI線程中對(duì)dom實(shí)現(xiàn)渲染。
?如下圖,是生成dom,dom的解析,映射,添加,渲染的流程。

?如上可知,因?yàn)镴S端運(yùn)行于獨(dú)立的單線程中,所以為了保證運(yùn)行的流暢性,一般需要避免在JS端執(zhí)行耗時(shí)操作,比如:網(wǎng)絡(luò)請(qǐng)求,圖片加載等,其實(shí)都是在原生端完成,js端執(zhí)行的是發(fā)起一個(gè)請(qǐng)求和響應(yīng)一個(gè)結(jié)果。同時(shí)因?yàn)樵伺cJS端是通過JS Bridge通訊,所以也需要盡量避免大數(shù)據(jù)和頻繁的通訊,導(dǎo)致響應(yīng)的延遲。
?原生端的dom的加載解析映射,也是性能的一大瓶頸。一般而言,Weex在Web端生成的,是通過webpack的webConfig打包成單頁面的index.web.js文件;而在原生端,一般會(huì)通過webpack的weexEntry配置成多頁面形式:即每一個(gè)需要獨(dú)立的.vue的頁面,最終會(huì)被打包成一個(gè).js文件。所以打開每個(gè)頁面時(shí)加載對(duì)應(yīng)的js文件,這很好的減小了需要加載的文件大小,提高了dom的解析效率。最后,Weex默認(rèn)打的js只包含業(yè)務(wù)js代碼,基礎(chǔ)js庫已經(jīng)被包含在weex sdk中,也使得體積會(huì)小很多。
三、入門
1、配置環(huán)境
?程序員就要從配置環(huán)開始,Weex 環(huán)境搭建 ,點(diǎn)擊鏈接,只要你要一個(gè)穩(wěn)定的網(wǎng)絡(luò),參考官網(wǎng)搭建環(huán)境,也就一杯茶的功夫,take it easy。配置好之后,weex create testProject創(chuàng)建一個(gè)項(xiàng)目High起來吧。
2、快速入門
?weex的入門還是比較簡單的,JavaScript、Vue了解下,即可預(yù)約的hello world。
?原生開發(fā)也許對(duì)vue接觸不多,跨界有時(shí)候很容易望而卻步,其實(shí)Vue本身,就是容易上手的框架,類似MVVM的模式(類似Android的DataBinding),很容讓人理解上手,簡單的說,你只關(guān)心數(shù)據(jù),然后綁定到顯示的控件,就是這么簡單。
?一般通過 Vue官網(wǎng) 教程,30分快速擼一發(fā),之后你就直接入門Weex了,對(duì),Weex做的最徹底的就是,你直接使用 vue 寫一個(gè)Web頁面,之后再順手編譯成了 ios 和 android 的原生頁面(盡管有些時(shí)候你需要在平臺(tái)適配上花費(fèi)心思)。

?如上圖(請(qǐng)忽略那個(gè)this( ̄. ̄)),這就是一個(gè)極度簡化的,用Vue寫的Weex頁面。效果是從顯示Hello World ,一秒變I’m CarGuo,就是這么自信。
?在<template>中排布需要渲染的控件,在<style>中指定控件的樣式(當(dāng)然你也可以直接在<template>中),在<script>中寫數(shù)據(jù)獲取和處理邏輯等,是不是很簡單, Don’t be shy,Let's fuck it !
?因?yàn)樾枰С秩?,Weex在Vue的基礎(chǔ)上閹割了一些標(biāo)簽、css樣式和事件,具體可見與 Web 平臺(tái)的差異
?其中,在Android和IOS上,<text> <image>等標(biāo)簽,其實(shí)是被編譯為原生控件,這就是上面所說的dom解析,同時(shí)你也可以在原生端,自定義控件或者功能模塊,然后注冊(cè)到weex中使用,實(shí)際上weex提供的基礎(chǔ)控件和功能模塊并不多,但卻很容易拓展,具體可見 拓展原生端功能 。
(ps 也不知道阿里是怕做多錯(cuò)多,還是懶)
?說到這里,就需要說一說Weex的原生插件開發(fā)支持,這也是官方文檔比較沒整理好的原因,其實(shí)文檔是有的:Weex插件開發(fā)文檔,如Android插件大致流程就是:
-
weex plugin create命令創(chuàng)建插件。 - 在android目錄的library下通過
@WeexComponent(控件)、@WeexModule(非UI功能)、@WeexAdapter(weex繼承功能拓展)實(shí)現(xiàn)第三方支持。 - 將library發(fā)布到maven (當(dāng)然你也可以直接源碼發(fā)布到npm)
- 配置根目錄的
package.json然后發(fā)布到npm
?由此可見,weex可以很方便的提供原生功能的拓展支持,但是由于社群較為薄弱,導(dǎo)致第三方插件缺失,有(hen)些(duo)時(shí)候你可能不得不自己著手,開發(fā)原生端的功能支持,這就對(duì)于跨平臺(tái)開發(fā)而言,特別前端開發(fā)而言,就稍(te)顯(bie)不友好了。

? 題外話 :說到跨平臺(tái)開發(fā),也許你聽說過cordova這位老大哥,它曾是早期的跨平臺(tái)開發(fā)潮流,cordova提供豐富的原生插件和打包功能:通過webview把前端頁面打包成一個(gè)App,通過插件提供前端需要的原生接口,交互通過webview的js接口支持。為什么說起它呢,是因?yàn)閃eex中,你可以看到很多cordova的影子,類似weex platform add android、weex plugin add xxx都有些cordova的味道。如下圖,你如今依舊可以在Weex中找,尋找到cordova的存在感。

3、其他推薦
? Vuex 和 Vue-Router ,居家旅行必不可少。
Vuex類似Redux,如果你沒聽說Redux不要緊,也不要慫,簡單了說,Vuex就是單頁面下,幫你管理數(shù)據(jù)的框架。數(shù)據(jù)都存在Vuex的store中,你操作store更新數(shù)據(jù),然后將store綁定到界面。它的用處在于可以在多個(gè)vue組件間,方便的同步數(shù)據(jù),更新界面。
Vue-Router也是用于單頁面下,指定跳到某個(gè)頁面的管理工具,路由嘛,淺顯易懂。
? iconfont :矢量圖標(biāo),少不了iconfont,通過字庫生成圖標(biāo),資源豐富,絕對(duì)值得推薦。
? weex-ui: weex中難得的良心官方封裝庫。
? eros :eros 不是框架,是基于 weex 封裝、面向前端的 vue 寫法的一整套 APP 開源解決方案,是由本木醫(yī)療大前端團(tuán)隊(duì)經(jīng)過大量實(shí)踐沉淀而出。。
四、深入填坑
1、ES6、ES7
? 說到 Javascript ,ES6、ES7必須了解下。Weex中默認(rèn)就有對(duì)其支持,但是對(duì)于async、await等,還需要如下一些簡單配置,然后 have fun 。
//命令行安裝
npm install --save-dev babel-plugin-transform-runtime
//然后在.babelrc文件中加入
{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}
2、多頁面
?Weex默認(rèn)是單頁面效果,也就是Android中一個(gè)Activity的概念,而單頁面效果在原生上,跳轉(zhuǎn)一多效果就會(huì)web了。既然叫native,怎么可能如此too young,所以這個(gè)時(shí)候,就需要修改默認(rèn)的webpack,讓其支持naive多頁面了?╮(╯▽╰)╭。
?首先,要知道Weex真正運(yùn)行的是,通過entry.js作為入口文件文件,通過webpack,將.vue文件打包成index.js進(jìn)行使用。Look,多頁面的重點(diǎn),就是將獨(dú)立頁面的.vue文件,生成多個(gè)js文件。

?如上圖,參考entry.js文件,創(chuàng)建一個(gè)SecondPageEntry.js,作為SecondPage.vue的入口,用于webpack生成SecondPage.js頁面。
?什么?webpack沒聽說過怎么辦,No problem,你只需簡單的修改,一知半解完全可以勝任。如下圖,我們主要需要修改webpack.common.conf.js文件,

?可以看出,webpack.common.conf.js中,其實(shí)是區(qū)分了webConfig和weexConfig的不同打包方式。如下圖,其中weexEntry就是我們需要修改的地方,可以看到本來已經(jīng)有index和entry.js存在了。

?最后我們需要通過navigator來實(shí)現(xiàn)跳轉(zhuǎn),我們需要知道,要跳轉(zhuǎn)的js文件在哪里,如下代碼演示,如何實(shí)現(xiàn)navigotor的native跳轉(zhuǎn),完整兼容三端跳轉(zhuǎn)請(qǐng)移步demo項(xiàng)目。
//獲取當(dāng)前js文件所在完整路徑
let bundleUrl = this.$getConfig().bundleUrl;
bundleUrl = String(bundleUrl);
let nativeBase;
//android一般位于file://assets目錄下
let isAndroidAssets = bundleUrl.indexOf('file://assets/') >= 0;
//ios一般位于一般帶有file開頭,帶有WeexDemo.app
let isiOSAssets = bundleUrl.indexOf('file:///') >= 0 && bundleUrl.indexOf('WeexDemo.app') > 0;
if (isAndroidAssets) {
nativeBase = 'file://assets/dist/';
} else if (isiOSAssets) {
nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
} else {
let host = 'localhost:8080';
let matches = /\/\/([^\/]+?)\//.exec(bundleUrl);
if (matches && matches.length >= 2) {
host = matches[1];
}
nativeBase = 'http://' + host + '/index.html?page=./dist/';
}
return nativeBase;
3、樣式sass\scss
?sass,后期必不可少的利器。
?當(dāng)你的weex項(xiàng)目不斷變大,一些樣式共享,公共顏色,大小尺寸等的管理,就是你需要面對(duì)的問題。
?這時(shí)候sass和scss就可以起到很大的作用。最大優(yōu)點(diǎn)是,它可編程,支持定義變量,而且不像閹割后的css一樣,var()這種寫法無法在native下得到支持,這時(shí)候sass的效果絕對(duì)讓你回味無窮。
?使用sass也十分簡單,簡單配置下webpack,sass的語法也十分容易上手,只需十分鐘了解下就可以愉快的享用這塊糖了。
- 先安裝sass依賴:
npm install node-sass;
npm install sass-loader; //依賴node-sass
- 之后
webpack.common.conf.js中配置loader,如下圖,在兩個(gè)module處,增加紅框配置。

- 最后用 import 引入的sass文件進(jìn)行加載,詳細(xì)可查看demo工程。
//也可以 lang="scss"
<style lang="sass">
//導(dǎo)入寫好的文件
@import "./style.scss";
</style>
五、蹲坑
?其實(shí)就是問題集錦,記錄一些開發(fā)過程中遇到的問題,相信你會(huì)喜歡:
1、關(guān)于vue的
<scrpit>標(biāo)簽內(nèi),weex.requireModule(包括插件weex-ui)中,在全局獲取返回null的原因,是因?yàn)閑ntry.js中的router對(duì)象,不能用import 和 export default,只能用require 和 module.exports 配合。2、es6一些語法問題,如async和await,可以用"babel-plugin-transform-runtime",在.babelrc中設(shè)置。
{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}
3、export default 和require混合使用的時(shí)候,會(huì)多一個(gè)default對(duì)象,比如this.$store.default.state這樣才對(duì)的問題。
4、自定義的js文件類中,不能使用全局的
weex.requireModule。5、使用weex-ui的tabbar結(jié)合是,
<list>必須有高度,或者overflow屬性為scroll才能滑動(dòng),而且overflow的位置必須是不會(huì)影響其他頁面位置。6、全屏默認(rèn)height 1334 和 width 750,但是記得減去32大概高度的statusbar。
7、list的loadmore,必須給list設(shè)置高度樣式,才能在web中正常觸發(fā)。
8、text的
</text>結(jié)束標(biāo)簽換行,在debug下可能會(huì)出現(xiàn)樣式問題。9、生命周期在web中與android等不同,比如activated等。
10、()=> {}對(duì)于this可能獲取存在的不同,盡量用function(){}。
11、多頁即創(chuàng)建多個(gè)類似entry.js的入口文件,在webpack下配置weex的打開生成的js文件,用于navigator跳轉(zhuǎn),通過url傳值。
12、android多頁面打開失敗
android.os.FileUriExposedException問題:
在你的Application中添加:
if (Build.VERSION.SDK_INT>=18) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}
ActivityNotFoundException問題:
<activity
android:name=".xxxxxx"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="com.taobao.android.intent.action.WEEX"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.taobao.android.intent.category.WEEX"/>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:scheme="file"/>
<data android:scheme="wxpage" />
</intent-filter>
</activity>
13、多頁面生成js時(shí),import的時(shí)候,需要指定.vue后綴的。
14、如果是webstorm,記得對(duì).temp dist node_modules platforms幾個(gè)文件夾,右鍵設(shè)置excluded,避免一直indexing和硬盤資源消耗。
15、@viewappear="onappear" @viewdisappear ="ondisappear" 類似onPause和onResume
16、ios實(shí)時(shí)看log,可以先增加
-(void)redirectConsoleLog{
#ifdef DEBUG
NSString *documentDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSLog(@"documentPath : %@",documentDir);
//重定向NSLog
NSString* logPath = [documentDir stringByAppendingPathComponent:@"console.log"];
freopen([logPath fileSystemRepresentation], "a+", stderr);
#endif
}
//調(diào)用
[self redirectConsoleLog];
然后在Devices下,找到對(duì)應(yīng)的模擬器號(hào)碼,在再Application下,搜索console.log,跟蹤執(zhí)行
tail -f
/Users/your name/Library/Developer/CoreSimulator/Devices/FDEACA11-D84E-4E8F-A6B8-26239559A928/data/Containers/Data/Application/9394D6CC-6B4A-4200-A13D-0CBE6F2BB67A/Documents/console.log
最后
1、文章配套,超完整 Weex 項(xiàng)目了解下:https://github.com/CarGuo/GSYGithubAppWeex
2、react native相關(guān)文章
從Android到React Native開發(fā)(一、入門)
從Android到React Native開發(fā)(二、通信與模塊實(shí)現(xiàn))
從Android到React Native開發(fā)(三、自定義原生控件支持)
從Android到React Native開發(fā)(四、打包流程和發(fā)布為Maven庫)
