Weex 詳細(xì)入坑之旅

一、與 Weex 的緣分

公司接了一個(gè)新項(xiàng)目,項(xiàng)目本身也不是很復(fù)雜于是我們老大說(shuō)希望用 Weex 進(jìn)行跨平臺(tái)開(kāi)發(fā),積累跨平臺(tái)方面的經(jīng)驗(yàn),由于我一直是做原生開(kāi)發(fā)的所以剛開(kāi)始是有點(diǎn)拒絕的,但內(nèi)心還是很蠢蠢欲動(dòng)的,所以我重新拾起了往年的前端基礎(chǔ) + 啃了兩本 js 書(shū)后開(kāi)始開(kāi)發(fā),經(jīng)過(guò)幾個(gè)月的實(shí)際開(kāi)發(fā)與體驗(yàn),我所負(fù)責(zé)的項(xiàng)目暫時(shí)告一段落了,于是趁著機(jī)會(huì)進(jìn)行個(gè)總結(jié),所以這篇博客就應(yīng)運(yùn)而生了, 現(xiàn)在的跨平臺(tái)框架挺多的而且大前端概念的火熱和趨勢(shì)席卷中國(guó)互聯(lián)網(wǎng),說(shuō)實(shí)話(huà)對(duì)于我們移動(dòng)端的沖擊不是一般的大,其實(shí)我一直都有關(guān)注技術(shù)的更新?lián)Q代和趨勢(shì)熱潮,大前端 和 Web 化對(duì)于公司來(lái)說(shuō)無(wú)疑是一種快遞迭代和節(jié)省成本的一種方式,所以興起算是一種必然吧!同時(shí)這也時(shí)刻警醒我們這些 IT 從業(yè)人員不想過(guò)時(shí)的話(huà)就要時(shí)刻有擁抱變化的準(zhǔn)備。

二、Weex 介紹

這里我就不多說(shuō)了直接引用 Weex 官網(wǎng)的介紹:

Weex 致力于使開(kāi)發(fā)者能基于通用跨平臺(tái)的 Web 開(kāi)發(fā)語(yǔ)言和開(kāi)發(fā)經(jīng)驗(yàn),來(lái)構(gòu)建 Android、iOS 和 Web 應(yīng)用。簡(jiǎn)單來(lái)說(shuō),在集成了 WeexSDK 之后,你可以使用 JavaScript 語(yǔ)言和前端開(kāi)發(fā)經(jīng)驗(yàn)來(lái)開(kāi)發(fā)移動(dòng)應(yīng)用。Weex 渲染引擎與 DSL 語(yǔ)法層是分開(kāi)的,Weex 并不強(qiáng)依賴(lài)任何特定的前端框架。目前 Vue.jsRax 這兩個(gè)前端框架被廣泛應(yīng)用于 Weex 頁(yè)面開(kāi)發(fā),同時(shí) Weex 也對(duì)這兩個(gè)前端框架提供了最完善的支持。Weex 的另一個(gè)主要目標(biāo)是跟進(jìn)流行的 Web 開(kāi)發(fā)技術(shù)并將其和原生開(kāi)發(fā)的技術(shù)結(jié)合,實(shí)現(xiàn)開(kāi)發(fā)效率和運(yùn)行性能的高度統(tǒng)一。在開(kāi)發(fā)階段,一個(gè) Weex 頁(yè)面就像開(kāi)發(fā)普通網(wǎng)頁(yè)一樣;在運(yùn)行時(shí),Weex 頁(yè)面又充分利用了各種操作系統(tǒng)的原生組件和能力。

看起來(lái)是不是很牛逼 ?如果你信了~ 嘖嘖嘖 騷年你還是 too young 啊 ~

三、Weex 大致原理

image.png
上面是 Weex 的架構(gòu)圖,從圖中我們也能大致看出 Weex 的大致工作流程

1、首先 Weex 會(huì)將編寫(xiě)的 Weex File 通過(guò) weex-toolkit 的轉(zhuǎn)換器 transformer 轉(zhuǎn)換成 JS Bundle

2、轉(zhuǎn)換的 JS Bundle 可以部署到服務(wù)端,方便 Web、Android、IOS 各終端請(qǐng)求相應(yīng)頁(yè)面從而實(shí)現(xiàn) hot reload, 當(dāng)然不部署到服務(wù)端是否可以呢? 答案是可以的,如果不部署到服務(wù)端在你 run android 的時(shí)候回自動(dòng)把 JS Bundle 放到 assets 目錄中,只是這樣就失去了 hot reload 作用

3、 當(dāng)請(qǐng)求到服務(wù)端的頁(yè)面后,各個(gè)終端通過(guò) Weex 的 JS Framework 接收和執(zhí)行 JS Bundle 代碼,并且完成數(shù)據(jù)綁定、模板編譯等操作,然后輸出 JSON 格式的 VIrtual DOM, DOM 生成后接下來(lái)就是將 DOM 渲染成本地原生控件,并且通過(guò) JS-Native Bridge 實(shí)現(xiàn) JS Framework 和 Native 的通信

四、 Weex 環(huán)境搭建

1、 官方搭建教程

  • 環(huán)境這個(gè)沒(méi)啥好說(shuō)的,按照官網(wǎng)配置就完事了,但是有幾個(gè)點(diǎn)還是要注意一下的,由于眾所周知的原因如果你無(wú)法科學(xué)上網(wǎng)的話(huà)那么還是有必要做一下 taobao 鏡像的,就算你能科學(xué)上網(wǎng)我也建議配置,因?yàn)槲冶荒窃愀獾木W(wǎng)速折騰的沒(méi)脾氣,就算 npm install 成功了還老是報(bào)莫名其妙的錯(cuò)誤,命令如下:

npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g weex-toolkit

  • 前端開(kāi)發(fā)環(huán)境支持
    我用的是 Jetbrains 的 WebStorm 進(jìn)行的開(kāi)發(fā),當(dāng)然如果你不喜歡WebStorm 也可以換 VSCode 或者其他輕量級(jí)編輯器

  • Android 環(huán)境支持
    配置Android開(kāi)發(fā)環(huán)境:安裝Java相關(guān)環(huán)境,安裝Android Studio及Android SDK。在安裝編譯Android項(xiàng)目時(shí)需要保證Android build-tool的版本為23.0.2以上。

  • IOS環(huán)境支持
    配置iOS開(kāi)發(fā)環(huán)境:安裝Xcode、cocoaPods及其相關(guān)環(huán)境。(需要 MacOs)

2、 一些注意事項(xiàng)

  • Android/IOS 項(xiàng)目必須保證要在 AndroidStudio 或 Xcode 中能夠運(yùn)行起來(lái),否則通過(guò) weex run andorid/ios 的話(huà)可能無(wú)法 build success !

  • 由于 Weex 是通過(guò) Vue.js 或 Rax.js 進(jìn)行頁(yè)面編寫(xiě),所以如果要想玩 Weex 的話(huà)可能需要有一定的 Html+CSS+JavaScript+Vue.js/Rax.js 基礎(chǔ)否則無(wú)法愉快的玩耍,但是光懂前端也是不行的如果你沒(méi)有一定的移動(dòng)端原生基礎(chǔ)那么遇到問(wèn)題你可能會(huì)崩潰~

    Vue.js 官網(wǎng)
    Rax.js 官網(wǎng)

  • Weex 支持 hot reload 在運(yùn)行時(shí)會(huì)自動(dòng)監(jiān)控你的頁(yè)面變動(dòng)達(dá)到實(shí)時(shí)刷新的效果,這點(diǎn)真的非常 nice

  • weex 支持 Vue.js 進(jìn)行頁(yè)面開(kāi)發(fā)看到這里是不是很開(kāi)心? 那我只能說(shuō)那只是你以為,從架構(gòu)圖中可以看到通過(guò) Vue.js 編寫(xiě)的組件在 Android 和 IOS 端上最終都是要渲染成原生控件的,所以這就導(dǎo)致 Weex 不可能支持 Vue.js 的全部特性根據(jù)不同平臺(tái)可能有些特性支持有些不支持,比如 Weex 的尺寸只支持 px 不支持 rem ,對(duì)于這些問(wèn)題官網(wǎng)文擋中的樣式、事件一欄已經(jīng)進(jìn)行了詳細(xì)的說(shuō)明,如果你想玩的話(huà)那么務(wù)必把這些看完

3、 開(kāi)始玩耍
如果上述步驟全部完成沒(méi)有問(wèn)題的話(huà)那么恭喜你,你可以用 Weex 愉快的玩耍了

  • 瀏覽器成功頁(yè)面
    創(chuàng)建項(xiàng)目 weex create your-project-name
    啟動(dòng) npm start


    image.png
  • 移動(dòng)端 成功頁(yè)面
    添加 Android / ios 項(xiàng)目 weex platform add android / ios
    運(yùn)行 Android / ios 項(xiàng)目 weex run android / ios


    image.png
  • Weex 命令行官網(wǎng)介紹
    其實(shí) weex 的一些常用命令都在 package.json 中配置了如下圖所示

    image.png

五、Weex 的教程和一些常用庫(kù)以及 Github 上的一些參考項(xiàng)目

  • WeexPlus
    這是一個(gè) Weex 和 Android 進(jìn)行 native 通信調(diào)用的一個(gè)框架由于我的項(xiàng)目有這方面要求所以我將其源碼進(jìn)行了集成自己做了一些改動(dòng)用起來(lái)還是不錯(cuò)的(主要是我也沒(méi)找到第二個(gè)),遺憾的是不支持 IOS!

六、Weex 的一些神坑

6.0、吐槽

Weex 雖然號(hào)稱(chēng) write onec run everywhere, 但在實(shí)際開(kāi)發(fā)中并沒(méi)有那么順利,一些坑點(diǎn)官網(wǎng)也沒(méi)有明確說(shuō)明,而且 Weex 的社區(qū)是真的爛,如果需求官方提供的不能滿(mǎn)足那么就得自己手?jǐn)]了,輪子極其稀少,插件市場(chǎng)早就打不開(kāi)了而且根本就沒(méi)幾個(gè)插件,Google Baidu 上面資料少的可憐遇到問(wèn)題無(wú)法解決那么只能看源碼自己摸索了,對(duì)于新手不是很友好,官方文檔的例子我都懶得說(shuō)了,能在簡(jiǎn)單點(diǎn)嗎? 關(guān)于擴(kuò)展 module 方面光打印一行文字有什么用?而且整個(gè)項(xiàng)目已經(jīng)托管到 Apche 基金會(huì)了。。。 拜托阿里你也是國(guó)際公司了,以后開(kāi)源能走點(diǎn)心嗎??還有,說(shuō)是跨平臺(tái)(Android、IOS、移動(dòng) Web 端) 但實(shí)際開(kāi)發(fā)其實(shí)相差甚遠(yuǎn)至少移動(dòng) Web 端還是算了, 就拿 weex-ui 的組件庫(kù)來(lái)說(shuō),部分組件在 Web 端是直接不顯示的,而且三端兼顧無(wú)論是是開(kāi)發(fā)還是后期維護(hù)也是個(gè)神坑,所以我明確跟領(lǐng)導(dǎo)說(shuō)了只兼容 Android 和 IOS 端,而且就這也遇到了不少兼容問(wèn)題,有的地方 android 可以 IOS 卻不行,有的尺寸 Android 顯示沒(méi)問(wèn)題,IOS 顯示就變小了不少諸如此類(lèi)~~ 所以說(shuō)跨平臺(tái)并沒(méi)有那么美好啊~~

吐槽就到這里吧,畢竟我也改變不了,所以只能發(fā)發(fā)牢騷寫(xiě)個(gè)總結(jié)避免后來(lái)者踩坑!

下面的坑點(diǎn)主要是結(jié)合 GSYGithubAppWeex 項(xiàng)目和自己這幾個(gè)月開(kāi)發(fā)經(jīng)驗(yàn)所得,我的項(xiàng)目也大多參考的是這個(gè)項(xiàng)目在這里感謝 CarGuo 大神,所以如果你想快速上手 Weex 那么我建議你先把這個(gè)項(xiàng)目 run 起來(lái),這個(gè)項(xiàng)目中有常用的組件封裝,網(wǎng)絡(luò)封裝和一些常用依賴(lài)以及 Utils js ,省的你在自己找了。同時(shí)這些坑點(diǎn)也可在 CarGuo 大神的博客中找到,而且更詳細(xì),下列坑點(diǎn)主要是自己在開(kāi)發(fā)中實(shí)際遇到過(guò)的問(wèn)題。

參考博客地址 : Weex原理之帶你去蹲坑

6.1 Navigator VS router

頁(yè)面跳轉(zhuǎn)是一個(gè)基本功能對(duì)此 Weex 提供了兩種方式,一種是通過(guò) router 的方式進(jìn)行跳轉(zhuǎn)一種是通過(guò) Weex 提供的本地跳轉(zhuǎn)方式 navigator 模塊進(jìn)行跳轉(zhuǎn),想要知道兩者的區(qū)別我們還是從使用方式來(lái)說(shuō)

  • Router
    router 是 Vue 提供的一種頁(yè)面跳轉(zhuǎn)方式通過(guò) router.push router.replace 進(jìn)行跳轉(zhuǎn), 在 Weex 中也能使用但體驗(yàn)極差,沒(méi)有任何過(guò)渡動(dòng)畫(huà),跳轉(zhuǎn)極其生硬和 Web 頁(yè)面跳轉(zhuǎn)一樣而且頁(yè)面跳轉(zhuǎn)后的任務(wù)棧結(jié)構(gòu)可能需要自己記錄,所以不予采用。
  • Navigator
    作為 weex 內(nèi)置的跳轉(zhuǎn)模塊 Navigator 所使用的跳轉(zhuǎn)是完全的本地跳轉(zhuǎn)方式,這樣的話(huà)過(guò)渡動(dòng)畫(huà)直接再本地統(tǒng)一配置即可而且也不用在單獨(dú)記錄頁(yè)面的任務(wù)棧,這也是 Weex 推薦的跳轉(zhuǎn)方式。但 Navigator 使用起來(lái)還是稍微有些繁瑣的,但并不復(fù)雜,只需按如下步驟即可:

第一步

創(chuàng)建一個(gè)你要跳轉(zhuǎn)的 Vue 頁(yè)面例如 JumpDemo.vue

第二步

在 src 目錄下創(chuàng)建一個(gè) entry 目錄,創(chuàng)建一個(gè)同名的 JumpDemo.js 文件里面加入如下代碼:

import store from '../store'
import mixins from '../mixins/index'
import * as filters from '../filter/filter'
import JumpDemo from '../components/JumpDemo.Vue

Object.keys(filters).forEach(key => {
    Vue.filter(key, filters[key])
})

Vue.mixin(mixins)

new Vue(Vue.util.extend({el: '#root', store}, JumpDemo))

第三步

在項(xiàng)目根目錄 -> configs -> webpack.common.conf.js 中的 const weexEntry 對(duì)象中加入如下代碼:

const weexEntry = {
    'index': helper.root('entry.js'),
    'JumpDemo': helper.root('entry/JumpDemo.js')
}

第四步 <主要指 Android 端>

這一步很重要,你可以新建一個(gè) Activity 頁(yè)面例如 WXPageSampleActivity 里面的內(nèi)容可以直接Copy WxPageActivity 中的代碼,然后在 AndroidManifest.xml 中添加如下代碼:

 <activity
    android:name=".WXPageSampleActivity"
    android:label="@string/app_name"
    android:screenOrientation="portrait">
    <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>

通過(guò)以上四步即可使用 Navigator 進(jìn)行頁(yè)面的跳轉(zhuǎn)了,具體如何跳轉(zhuǎn)請(qǐng)查看 weex 官方文檔

6.2 全局的頁(yè)面狀態(tài)管理

Vuex 非常適合 Vue 在單頁(yè)面下的全局狀態(tài)管理,但一旦涉及到多頁(yè)面就沒(méi)什么作用了,因?yàn)槊恳粋€(gè) Navigator 頁(yè)面都是一個(gè)單頁(yè)應(yīng)用,所以本項(xiàng)目中后面基本用內(nèi)置模塊 storage 來(lái)代替 Vuex 的作用。

6.3 text 組件換行

weex 是比較推薦使用 iconfont 來(lái)展示一些應(yīng)用圖標(biāo)的其中 text 通過(guò)簡(jiǎn)單配置可以用來(lái)展示 iconfont 圖標(biāo),但是 text 組件有個(gè) bug 那就是一旦標(biāo)簽換行那么 iconfont 就不顯示了。 (weex sdk 0.16.0 )

6.4 全局 module 問(wèn)題

自定義 js 文件中不能使用全局的 weexModule

6.5 async 、await 支持

async 、await 支持需要在 .babelrc 文件中配置


{
 "presets": [
   "es2015",
   "stage-0"
 ],
 "plugins": [ [
   "transform-runtime",
   {
     "helpers": false,
     "polyfill": false,
     "regenerator": true,
     "moduleName": "babel-runtime"
   }
 ]]
}

6.6 weex-ui的tabbar

和weex-ui的tabbar結(jié)合,list必須有高度,或者overflow為scroll才能滑動(dòng),而且overflow的位置必須是不會(huì)影響其他頁(yè)面的

6.7 width and height

全屏默認(rèn)height 1334 和 width 750,但是記得減去32大概高度的statusbar。

6.8 android多頁(yè)面打開(kāi)失敗

android.os.FileUriExposedException問(wèn)題:

在你的Application中添加:

if (Build.VERSION.SDK_INT>=18) {
    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());
    builder.detectFileUriExposure();
}

ActivityNotFoundException問(wèn)題:

 <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>
 
6.9 Weex 的列表組件

Weex 提供的列表組件我真的是無(wú)力吐槽,列表展示沒(méi)什么問(wèn)題,但如果展示九宮格那真的是惡心到我了,不像我們 Android 使用 RecyclerView 指定 GridLayoutManager 就可以展示九宮格列表, Weex 只能從數(shù)據(jù)上下功夫,可能我沒(méi)找到相應(yīng)的方法?? 反正我是沒(méi)找到

  • 展示列表的數(shù)據(jù)類(lèi)型很簡(jiǎn)單就一個(gè)數(shù)組就行
list : [
  {title:'hello',value:'world'},
  {title:'hello',value:'world'},
  {title:'hello',value:'world'},
]

<list>
    <cell v-for="(item, index) in list">
       <div :style="{width:'750px'}">
            <div class="cell-container row align-center">//樣式需要自己定義
                <text class="item-text" >{{item.title}}</text>
                <text class="item-text" >{{item.value}}</text>
            </div>
        </div>
      </cell>
</list>
  • 展示九宮格列表的數(shù)據(jù)就沒(méi)那么方便如下所示,一行展示幾列那么控制 list 中的元素就行
gridList : [
 { 
   list: [
    {title:'hello',value:'world'},
    {title:'hello',value:'world'},
    {title:'hello',value:'world'},
  ],
 },
 { 
   list: [
    {title:'hello',value:'world'},
    {title:'hello',value:'world'},
    {title:'hello',value:'world'},
  ],
 }
]

<list :style="{width:'750px'}">
 <cell class="rows " v-for="(group, i) in gridList" :key="i">
  <div class="item center" v-for="(data, j) in group.list">
    <div class="item-back center" :style="{width:'220px',height:'220px'}">
      <div class="column" :style="{width:'220px'}">
        <text :style="{fontSize:'26px'}">{{data.title}}</text>
        <text :style="{fontSize:'26px'}">{{data.value}</text>
     </div>
    </div>
   </div>
  </cell>
</list>

可是這種數(shù)據(jù)格式寫(xiě)著也太費(fèi)勁了,我給服務(wù)端同事看他也是老大不愿意,所以我只好自己設(shè)計(jì)了一個(gè)轉(zhuǎn)換函數(shù)如下

/**
 * 由于 weex 的網(wǎng)格列表展示原因,目前沒(méi)有找到好的解決方案
 * 所以寫(xiě)了此方法將任意數(shù)組轉(zhuǎn)換為weex能展示的網(wǎng)格數(shù)據(jù)格式
 * 例如傳入 list = [1,2,3,4,5] 將會(huì)轉(zhuǎn)換為如下格式
 *
 * [{[1,2,3]},{[4,5]}]
 *
 * @param list 傳入的數(shù)組集合
 * @param num 水平方向幾條數(shù)據(jù)
 */
export function convertToGrid(list, num) {
    if (!list) {
        return false;
    }
    let index = 0;
    for (let i = 1; i < list.length + 1; i++) {
        if (i < list.length && i % num === 0) {
            index++;
        } else if (i === list.length) {
            index++;
        }
    }
    console.log('index : '+index);
    let x = 0;
    let tempList = [];
    for (let i = 0; i < index; i++) {
        let obj = {};
        let data = [];
        for (let j = 0; j < num; j++) {
            data.push(list[x]);
            x++;
            if (x === list.length) {
                break;
            }
        }
        obj = {data};
        tempList.push(obj);
    }
    return tempList;
}

七、總結(jié)

Weex 這款框架總體還是很不錯(cuò)的,畢竟沒(méi)有 RN 那么重很輕量級(jí)的一個(gè)框架,不過(guò)論社區(qū)維護(hù)和資料文獻(xiàn) Weex 可以說(shuō)基本沒(méi)有,輪子太少,這就讓開(kāi)發(fā)的效率會(huì)變得很低,而且如果要調(diào)用移動(dòng)端的原生功能還是需要 Android / IOS 開(kāi)發(fā)人員的支持的成本也沒(méi)減多少,而且從我實(shí)際的體驗(yàn)來(lái)說(shuō) Weex 真心不適合全應(yīng)用開(kāi)發(fā),只適合嵌入到原生頁(yè)面中使用,比如某個(gè)頁(yè)面可能因?yàn)闃I(yè)務(wù)頻繁的變動(dòng)那么這個(gè)時(shí)候就可以考慮嵌入 Weex 頁(yè)面實(shí)現(xiàn) hot reload 避免頻繁發(fā)版,但如此我還是不建議使用 Weex 這個(gè)框架,開(kāi)發(fā)過(guò)程實(shí)在讓我一言難盡,如果能重來(lái),我選擇擁抱 Flutter ~~ 阿里這個(gè) KPI 項(xiàng)目還是有哪涼快哪待著去吧~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容