本篇將節操滿滿的安利Weex(˶‾᷄ ⁻̫ ‾᷅˵),不一樣的角度推薦你入坑,官網有的我們不拖泥,這裡將給你補充官方沒有的,深入到蹲坑給你排憂解難,總會給你點驚喜,內容越後越幹,請緊張的往下看。
***** 本文配套,超完整 Weex 專案推薦 : GSYGithubAppWeex *****
一、簡介
有對比才有傷害,說到Weex,難免讓人聯絡React Native。雖同為跨平臺移動端解決方案,擁JavaScript妄一統天下,單兩者的設計理念其實截然不同。
這裡先介紹下兩者的差異,給徘徊在 React Native 和 Weex 之間的人,理解更適合哪些場景。
型別 | React Native | Weex |
---|---|---|
效能 | 較好 | 較弱 |
上手難度 | 稍高 | 容易 |
核心理念 | React | Vue |
框架程度 | 較重 | 較輕 |
特點 | 適合開發整體App | 適合單頁面 |
社群 | 豐富,Facebook維護 | 略殘念,目前託管apache |
支援 | Android、IOS | Android、IOS、Web |
適應性 | 原生開學習成本低 | Web開發學習成本低 |
JS引擎 | JSCore | V8 |
作為兩個框架的深度體驗者,個人總結出上面的對比,其中可以看出:
-
React Native更適合開發完整的App,因為它的效能較好,第三方外掛豐富,社群活躍並且維護較好,文件完整等(本篇主角是Weex好吧魂淡(#゚Д゚))。
-
Weex更適合開發單頁面整合,這也是阿里的業務特性。
當然Weex也可以開發完整的多頁面App,同時我也是這麼用過,不過效果對比React Native,顯然強差人意。 -
Weex勝在容易上手,基於Vue的設計模式,類MVVM的實現,也讓前端能更無縫的實現一些高效能的App業務。
-
Weex相容Android、IOS、Web三端,在單頁面的實現上,它有著React Native無法睥睨的先天優勢。
-
Weex的社群,個人覺得還是弱,資料不足,文件簡單,第三方支援太弱。和React Native一樣支援帶原生功能的外掛開發,但是,支援太少了,這也提高了後期的開發門檻。同時,一個小問題很容易讓入初學者,三過門而不入,作為一個釋出了兩年的框架,還是比較讓人吐槽的。
二、原理
這裡簡要說明下Weex在android下的分層以及原理。
Weex主要包括三大部分:JS Bridge、Render、Dom,分別對應WXBridgeManager
、WXRenderManager
、WXDomManager
。通過WXSDKManager
統一管理。其中JS Bridge和Dom執行在獨立的HandlerThread中,而Render執行在UI執行緒。JS Bridge主要用來和 JS 端實現進行雙向通訊,比如把js端的dom結構傳遞給Dom執行緒。Dom主要是用於負責dom的解析、對映、新增等等的操作,最後通知UI執行緒更新。而Render負責在UI執行緒中對dom實現渲染。
如下圖,是生成dom,dom的解析,對映,新增,渲染的流程。
如上可知,因為JS端執行於獨立的單執行緒中,所以為了保證執行的流暢性,一般需要避免在JS端執行耗時操作,比如:網路請求,圖片載入等,其實都是在原生端完成,js端執行的是發起一個請求和響應一個結果。同時因為原生端與JS端是通過JS Bridge通訊,所以也需要儘量避免大資料和頻繁的通訊,導致響應的延遲。
原生端的dom的載入解析對映,也是效能的一大瓶頸。一般而言,Weex在Web端生成的,是通過webpack的webConfig
打包成單頁面的index.web.js
檔案;而在原生端,一般會通過webpack的weexEntry
配置成多頁面形式:即每一個需要獨立的.vue的頁面,最終會被打包成一個.js檔案。所以開啟每個頁面時載入對應的js檔案,這很好的減小了需要載入的檔案大小,提高了dom的解析效率。最後,Weex預設打的js只包含業務js程式碼,基礎js庫已經被包含在weex sdk中,也使得體積會小很多。
三、入門
1、配置環境
程式設計師就要從配置環開始,Weex 環境搭建 ,點選連結,只要你要一個穩定的網路,參考官網搭建環境,也就一杯茶的功夫,take it easy。配置好之後,weex create testProject
建立一個專案High起來吧。
2、快速入門
weex的入門還是比較簡單的,JavaScript、Vue瞭解下,即可預約的hello world。
原生開發也許對vue接觸不多,跨界有時候很容易望而卻步,其實Vue本身,就是容易上手的框架,類似MVVM的模式(類似Android的DataBinding),很容讓人理解上手,簡單的說,你只關心資料,然後繫結到顯示的控制元件,就是這麼簡單。
一般通過 Vue官網 教程,30分快速擼一發,之後你就直接入門Weex了,對,Weex做的最徹底的就是,你直接使用 vue 寫一個Web頁面,之後再順手編譯成了 ios 和 android 的原生頁面(儘管有些時候你需要在平臺適配上花費心思)。
如上圖(請忽略那個this( ̄. ̄)),這就是一個極度簡化的,用Vue寫的Weex頁面。效果是從顯示Hello World ,一秒變I’m CarGuo,就是這麼自信。
在<template>
中排布需要渲染的控制元件,在<style>
中指定控制元件的樣式(當然你也可以直接在<template>
中),在<script>
中寫資料獲取和處理邏輯等,是不是很簡單, Don’t be shy,Let`s fuck it !
因為需要支援三端,Weex在Vue的基礎上閹割了一些標籤、css樣式和事件,具體可見與 Web 平臺的差異
其中,在Android和IOS上,<text> <image>
等標籤,其實是被編譯為原生控制元件,這就是上面所說的dom解析,同時你也可以在原生端,自定義控制元件或者功能模組,然後註冊到weex中使用,實際上weex提供的基礎控制元件和功能模組並不多,但卻很容易擴充,具體可見 擴充原生端功能 。
(ps 也不知道阿里是怕做多錯多,還是懶)
說到這裡,就需要說一說Weex的原生外掛開發支援,這也是官方文件比較沒整理好的原因,其實文件是有的:Weex外掛開發文件,如Android外掛大致流程就是:
weex plugin create
命令建立外掛。- 在android目錄的library下通過
@WeexComponent
(控制元件)、@WeexModule
(非UI功能)、@WeexAdapter
(weex繼承功能擴充)實現第三方支援。 - 將library釋出到maven (當然你也可以直接原始碼釋出到npm)
- 配置根目錄的
package.json
然後釋出到npm
由此可見,weex可以很方便的提供原生功能的擴充支援,但是由於社群較為薄弱,導致第三方外掛缺失,有(hen)些(duo)時候你可能不得不自己著手,開發原生端的功能支援,這就對於跨平臺開發而言,特別前端開發而言,就稍(te)顯(bie)不友好了。
題外話 :說到跨平臺開發,也許你聽說過cordova
這位老大哥,它曾是早期的跨平臺開發潮流,cordova
提供豐富的原生外掛和打包功能:通過webview把前端頁面打包成一個App,通過外掛提供前端需要的原生介面,互動通過webview的js介面支援。為什麼說起它呢,是因為Weex中,你可以看到很多cordova
的影子,類似weex platform add android
、weex plugin add xxx
都有些cordova
的味道。如下圖,你如今依舊可以在Weex中找,尋找到cordova
的存在感。
3、其他推薦
Vuex 和 Vue-Router ,居家旅行必不可少。
-
Vuex類似Redux,如果你沒聽說Redux不要緊,也不要慫,簡單了說,Vuex就是單頁面下,幫你管理資料的框架。資料都存在Vuex的store中,你操作store更新資料,然後將store繫結到介面。它的用處在於可以在多個vue元件間,方便的同步資料,更新介面。
-
Vue-Router也是用於單頁面下,指定跳到某個頁面的管理工具,路由嘛,淺顯易懂。
iconfont :向量圖示,少不了iconfont,通過字型檔生成圖示,資源豐富,絕對值得推薦。
weex-ui: weex中難得的良心官方封裝庫。
eros :eros 不是框架,是基於 weex 封裝、面向前端的 vue 寫法的一整套 APP 開源解決方案,是由本木醫療大前端團隊經過大量實踐沉澱而出。。
四、深入填坑
1、ES6、ES7
說到 Javascript ,ES6、ES7必須瞭解下。Weex中預設就有對其支援,但是對於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預設是單頁面效果,也就是Android中一個Activity的概念,而單頁面效果在原生上,跳轉一多效果就會web了。既然叫native,怎麼可能如此too young,所以這個時候,就需要修改預設的webpack,讓其支援naive多頁面了ı╮(╯▽╰)╭。
首先,要知道Weex真正執行的是,通過entry.js
作為入口檔案檔案,通過webpack,將.vue
檔案打包成index.js
進行使用。Look,多頁面的重點,就是將獨立頁面的.vue
檔案,生成多個js檔案。
如上圖,參考entry.js
檔案,建立一個SecondPageEntry.js,作為SecondPage.vue的入口,用於webpack生成SecondPage.js頁面。
什麼?webpack沒聽說過怎麼辦,No problem,你只需簡單的修改,一知半解完全可以勝任。如下圖,我們主要需要修改webpack.common.conf.js
檔案,
可以看出,webpack.common.conf.js
中,其實是區分了webConfig和weexConfig的不同打包方式。如下圖,其中weexEntry就是我們需要修改的地方,可以看到本來已經有index和entry.js存在了。
最後我們需要通過navigator來實現跳轉,我們需要知道,要跳轉的js檔案在哪裡,如下程式碼演示,如何實現navigotor的native跳轉,完整相容三端跳轉請移步demo專案。
//獲取當前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、樣式sassscss
sass,後期必不可少的利器。
當你的weex專案不斷變大,一些樣式共享,公共顏色,大小尺寸等的管理,就是你需要面對的問題。
這時候sass和scss就可以起到很大的作用。最大優點是,它可程式設計,支援定義變數,而且不像閹割後的css一樣,var()這種寫法無法在native下得到支援,這時候sass的效果絕對讓你回味無窮。
使用sass也十分簡單,簡單配置下webpack,sass的語法也十分容易上手,只需十分鐘瞭解下就可以愉快的享用這塊糖了。
- 先安裝sass依賴:
npm install node-sass;
npm install sass-loader; //依賴node-sass
複製程式碼
- 之後
webpack.common.conf.js
中配置loader,如下圖,在兩個module處,增加紅框配置。
- 最後用 import 引入的sass檔案進行載入,詳細可檢視demo工程。
//也可以 lang="scss"
<style lang="sass">
//匯入寫好的檔案
@import "./style.scss";
</style>
複製程式碼
五、蹲坑
其實就是問題集錦,記錄一些開發過程中遇到的問題,相信你會喜歡:
-
1、關於vue的
<scrpit>
標籤內,weex.requireModule(包括外掛weex-ui)中,在全域性獲取返回null的原因,是因為entry.js中的router物件,不能用import 和 export default,只能用require 和 module.exports 配合。 -
2、es6一些語法問題,如async和await,可以用”babel-plugin-transform-runtime”,在.babelrc中設定。
{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}
複製程式碼
-
3、export default 和require混合使用的時候,會多一個default物件,比如this.$store.default.state這樣才對的問題。
-
4、自定義的js檔案類中,不能使用全域性的
weex.requireModule
。 -
5、使用weex-ui的tabbar結合是,
<list>
必須有高度,或者overflow屬性為scroll才能滑動,而且overflow的位置必須是不會影響其他頁面位置。 -
6、全屏預設height 1334 和 width 750,但是記得減去32大概高度的statusbar。
-
7、list的loadmore,必須給list設定高度樣式,才能在web中正常觸發。
-
8、text的
</text>
結束標籤換行,在debug下可能會出現樣式問題。 -
9、生命週期在web中與android等不同,比如activated等。
-
10、()=> {}對於this可能獲取存在的不同,儘量用function(){}。
-
11、多頁即建立多個類似entry.js的入口檔案,在webpack下配置weex的開啟生成的js檔案,用於navigator跳轉,通過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時,import的時候,需要指定.vue字尾的。
-
14、如果是webstorm,記得對.temp dist node_modules platforms幾個資料夾,右鍵設定excluded,避免一直indexing和硬碟資源消耗。
-
15、@viewappear=”onappear” @viewdisappear =”ondisappear” 類似onPause和onResume
-
16、ios實時看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
}
複製程式碼
//呼叫
[self redirectConsoleLog];
複製程式碼
然後在Devices下,找到對應的模擬器號碼,在再Application下,搜尋console.log,跟蹤執行
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 專案瞭解下:github.com/CarGuo/GSYG…
2、react native相關文章
從Android到React Native開發(二、通訊與模組實現)