Weex原理之帶你去蹲坑

 本篇將節操滿滿的安利Weex(˶‾᷄ ⁻̫ ‾᷅˵),不同的角度推薦你入坑,官網有的咱們不拖泥,這裏將給你補充官方沒有的,深刻到蹲坑給你排憂解難,總會給你點驚喜,內容越後越幹,請緊張的往下看。css

兩個字,講究

***** 本文配套,超完整 Weex 項目推薦 : GSYGithubAppWeex ***** html

1、簡介

 有對比才有傷害,說到Weex,不免讓人聯繫React Native。雖同爲跨平臺移動端解決方案,擁JavaScript妄一統天下,單二者的設計理念其實大相徑庭。前端

 這裏先介紹下二者的差別,給徘徊在 React Native 和 Weex 之間的人,理解更適合哪些場景。vue

類型 React Native Weex
性能 較好 較弱
上手難度 稍高 容易
核心理念 React Vue
框架程度 較重 較輕
特色 適合開發總體App 適合單頁面
社區 豐富,Facebook維護 略殘念,目前託管apache
支持 Android、IOS Android、IOS、Web
適應性 原生開學習成本低 Web開發學習成本低
JS引擎 JSCore V8

 做爲兩個框架的深度體驗者,我的總結出上面的對比,其中能夠看出:node

  • React Native更適合開發完整的App,由於它的性能較好,第三方插件豐富,社羣活躍而且維護較好,文檔完整等(本篇主角是Weex好吧魂淡(#゚Д゚))。react

  • Weex更適合開發單頁面集成,這也是阿里的業務特性。 固然Weex也能夠開發完整的多頁面App,同時我也是這麼用過,不過效果對比React Native,顯然強差人意。android

  • Weex勝在容易上手,基於Vue的設計模式,類MVVM的實現,也讓前端能更無縫的實現一些高性能的App業務。webpack

  • Weex兼容Android、IOS、Web三端,在單頁面的實現上,它有着React Native沒法睥睨的先天優點。ios

  • Weex的社羣,我的以爲仍是弱,資料不足,文檔簡單,第三方支持太弱。和React Native同樣支持帶原生功能的插件開發,可是,支持太少了,這也提升了後期的開發門檻。同時,一個小問題很容易讓入初學者,三過門而不入,做爲一個發佈了兩年的框架,仍是比較讓人吐槽的。git

這就是,所謂的前言吧

2、原理

 這裏簡要說明下Weex在android下的分層以及原理。

 Weex主要包括三大部分:JS BridgeRenderDom,分別對應WXBridgeManagerWXRenderManagerWXDomManager 。經過WXSDKManager統一管理。其中JS BridgeDom運行在獨立的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中,也使得體積會小不少。

3、入門

一、配置環境

 程序員就要從配置環開始,Weex 環境搭建 ,點擊連接,只要你要一個穩定的網絡,參考官網搭建環境,也就一杯茶的功夫,take it easy。配置好以後,weex create testProject建立一個項目High起來吧。

二、快速入門

 weex的入門仍是比較簡單的,JavaScript、Vue瞭解下,便可預定的hello world。

 原生開發也許對vue接觸很少,跨界有時候很容易望而卻步,其實Vue自己,就是容易上手的框架,相似MVVM的模式(相似Android的DataBinding),很容讓人理解上手,簡單的說,你只關心數據,而後綁定到顯示的控件,就是這麼簡單。

 通常經過 Vue官網 教程,30分快速擼一發,以後你就直接入門Weex了,對,Weex作的最完全的就是,你直接使用 vue 寫一個Web頁面,以後再順手編譯成了 ios 和 android 的原生頁面(儘管有些時候你須要在平臺適配上花費心思)。

請忽略那個this,真的( ̄. ̄)

 如上圖(請忽略那個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 androidweex plugin add xxx都有些cordova的味道。以下圖,你現在依舊能夠在Weex中找,尋找到cordova的存在感。

cordova殘留

三、其餘推薦
Vuex 和 Vue-Router ,居家旅行必不可少。
  • Vuex相似Redux,若是你沒據說Redux沒關係,也不要慫,簡單了說,Vuex就是單頁面下,幫你管理數據的框架。數據都存在Vuex的store中,你操做store更新數據,而後將store綁定到界面。它的用處在於能夠在多個vue組件間,方便的同步數據,更新界面。

  • Vue-Router也是用於單頁面下,指定跳到某個頁面的管理工具,路由嘛,淺顯易懂。

iconfont :矢量圖標,少不了iconfont,經過字庫生成圖標,資源豐富,絕對值得推薦。
weex-ui: weex中可貴的良心官方封裝庫。
eros :eros 不是框架,是基於 weex 封裝、面向前端的 vue 寫法的一整套 APP 開源解決方案,是由本木醫療大前端團隊通過大量實踐沉澱而出。。

4、深刻填坑

一、ES六、ES7

  說到 Javascript ,ES六、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"
}
]]
}
複製代碼
二、多頁面

 Weex默認是單頁面效果,也就是Android中一個Activity的概念,而單頁面效果在原生上,跳轉一多效果就會web了。既然叫native,怎麼可能如此too young,因此這個時候,就須要修改默認的webpack,讓其支持naive多頁面了ı╮(╯▽╰)╭。

 首先,要知道Weex真正運行的是,經過entry.js做爲入口文件文件,經過webpack,將.vue文件打包成index.js進行使用。Look,多頁面的重點,就是將獨立頁面的.vue文件,生成多個js文件。

入口js

 如上圖,參考entry.js文件,建立一個SecondPageEntry.js,做爲SecondPage.vue的入口,用於webpack生成SecondPage.js頁面。

 什麼?webpack沒據說過怎麼辦,No problem,你只需簡單的修改,只知其一;不知其二徹底能夠勝任。以下圖,咱們主要須要修改webpack.common.conf.js文件,

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;

複製代碼
三、樣式sass\scss

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>
複製代碼

5、蹲坑

 其實就是問題集錦,記錄一些開發過程當中遇到的問題,相信你會喜歡:

  • 一、關於vue的<scrpit>標籤內,weex.requireModule(包括插件weex-ui)中,在全局獲取返回null的緣由,是由於entry.js中的router對象,不能用import 和 export default,只能用require 和 module.exports 配合。

  • 二、es6一些語法問題,如async和await,能夠用"babel-plugin-transform-runtime",在.babelrc中設置。

{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}
複製代碼
  • 三、export default 和require混合使用的時候,會多一個default對象,好比this.$store.default.state這樣纔對的問題。

  • 四、自定義的js文件類中,不能使用全局的weex.requireModule

  • 五、使用weex-ui的tabbar結合是,<list>必須有高度,或者overflow屬性爲scroll才能滑動,並且overflow的位置必須是不會影響其餘頁面位置。

  • 六、全屏默認height 1334 和 width 750,可是記得減去32大概高度的statusbar。

  • 七、list的loadmore,必須給list設置高度樣式,才能在web中正常觸發。

  • 八、text的</text>結束標籤換行,在debug下可能會出現樣式問題。

  • 九、生命週期在web中與android等不一樣,好比activated等。

  • 十、()=> {}對於this可能獲取存在的不一樣,儘可能用function(){}。

  • 十一、多頁即建立多個相似entry.js的入口文件,在webpack下配置weex的打開生成的js文件,用於navigator跳轉,經過url傳值。

  • 十二、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>
複製代碼
  • 1三、多頁面生成js時,import的時候,須要指定.vue後綴的。

  • 1四、若是是webstorm,記得對.temp dist node_modules platforms幾個文件夾,右鍵設置excluded,避免一直indexing和硬盤資源消耗。

  • 1五、@viewappear="onappear" @viewdisappear ="ondisappear" 相似onPause和onResume

  • 1六、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
複製代碼

最後

一、文章配套,超完整 Weex 項目瞭解下:github.com/CarGuo/GSYG…

二、react native相關文章

從Android到React Native開發(1、入門)

從Android到React Native開發(2、通訊與模塊實現)

從Android到React Native開發(3、自定義原生控件支持)

從Android到React Native開發(4、打包流程和發佈爲Maven庫)

還記得我嗎
相關文章
相關標籤/搜索