Weex在內涵發現頁中的工程實踐
鑒于Weex在性能方面做過一些針對性的優化并且已在阿里的業務線上得到了規模性的應用,我們決定在內涵段子這個具備800萬日活的產品中嘗試應用Weex。這樣做的主要目的是為了深化對Weex的認識,與React Native進行對比分析,確立IES客戶端跨平臺方案的下一步研究方向。
一、工程實踐
1.1 準備工作
- 開發環境搭建: https://weex.incubator.apache.org/cn/guide/set-up-env.html
- 集成Weex SDK到已有應用: https://weex.incubator.apache.org/cn/guide/integrate-to-your-app.html
- 下載Weex Playground APP: https://weex.apache.org/cn/playground.html Weex Playground APP集成了Weex SDK,它內置了用于展示Weex組件功能的Demo。通過它的掃碼功能,還可以加載自己本地Server的Weex代碼進行調試(前提是手機和電腦在同一個局域網內)。
1.2 調試
1.2.1 調試環境
在Weex項目中,調試代碼的環境有三種:瀏覽器、Weex Playground APP、自己的應用內。
因為Weex的代碼可以同時兼容瀏覽器、iOS和安卓三種運行環境,因此可以在瀏覽器環境中調試Weex項目代碼。在Weex工程中運行npm run dev和npm run serve命令并在瀏覽器中訪問 http://localhost:8080 即可預覽Weex項目效果,如下圖所示。但是就目前的狀況來講,Weex對三端的兼容性支持還不是很完善,在瀏覽器中調試好的代碼再放到客戶端環境中運行還是有極大的可能會出問題,因此如果最終目標只是想在客戶端中運行Weex代碼,并不建議通過瀏覽器來調試。
Weex Playground APP集成了Weex SDK,可以通過它的掃碼功能來調試自己的Weex項目代碼。項目開始時,如果客戶端Weex集成工作還沒完成且調試環境還沒有準備好,可以使用Weex Playground APP來輔助調試,因為此時項目的主要工作還是編寫界面,并不需要客戶端擴展功能模塊的支持。
項目界面開發完成后,后面階段的調試工作就需要在自己的應用內進行了,因為此時一般需要客戶端擴展的功能模塊或組件的支持。例如,獲取網絡請求通用參數、打點、接收客戶端事件消息等。應用內集成了Weex SDK后,在需要調試Weex代碼的頁面,建議客戶端在DEBUG模式下提供刷新頁面按鈕以方便調試。
1.2.2 DEBUG
在React Native的開發中,可以通過點擊開發者菜單中的“Debug JS Remotely”選項來開啟JS代碼的遠程調試。然而在Weex的開發中,開啟JS代碼遠程調試功能的步驟要麻煩一些,需要在應用內集成Weex DevTools工具。由于Weex Playground APP已經集成了Weex DevTools工具,可以使用Weex Playground APP來試驗一下如何使用weex-toolkit里面提供的調試工具。
首先,在命令行中運行weex debug命令,該命令會啟動一個調試服務器,并同時喚起Chrome瀏覽器打開調試主頁,如下圖所示。
然后,打開Weex Playground APP掃描調試主頁下方的二維碼,即可在應用與調試服務器之間建立socket連接并向調試服務器注冊應用信息,如下圖所示。
此時,點擊上圖中的Debugger按鈕可以開啟JavaScript代碼的遠程調試功能,在ChromeDevTools里面對Weex工程的JavaScript代碼進行調試;點擊Inspector按鈕可以查看Weex頁面的element屬性結構。
如果想使用weex-toolkit提供的調試工具對自己應用內的Weex頁面進行調試,必須先在應用內集成Weex DevTools。具體集成方法請參考:集成 DevTools 到 iOS和集成 DevTools 到 Android。
1.3 開發
此次Weex應用于內涵的發現頁,發現頁的UI如下面三張圖所示。發現頁有以下特征:
- 由熱吧和訂閱兩個列表頁組成,通過頂TAB進行切換;
- 熱吧和訂閱數據一次性加載完畢,無loadmore邏輯,熱吧數據大概在200~300條;
- 用戶可切換主題:白天模式和夜間模式。
1.3.1 組件劃分及布局
發現頁的頁面組成元素比較簡單,組件分為輪播圖組件、熱吧Cell組件以及訂閱吧Cell組件。
發現頁的文檔結構大致如下:
<div>
<!-- 頭部 -->
<div class="header"></div>
<!-- 熱吧列表 -->
<list class="hot-bar-list"></list>
<!-- 訂閱吧列表 -->
<list class="subscribed-bar-list"></list>
</div>
其中值得一提的是實現TAB切換的方式。一般來講,很容易想到使用vue的條件渲染來實現TAB的切換,如下:
<div>
<!-- 頭部 -->
<div class="header"></div>
<!-- 熱吧列表 -->
<list class="hot-bar-list" v-if="activTab === 'HOT'"></list>
<!-- 訂閱吧列表 -->
<list class="subscribed-bar-list" v-if="activTab === 'SUBSCRIBED'"></list>
</div>
但是這樣做會造成TAB切換時列表渲染卡頓,因為熱吧列表有200~300條數據,每次切換都重新渲染一次會造成較大的性能消耗。因此,在實現的時候對list采用了絕對定位的布局方式,在TAB切換的時候,將已經渲染好的列表結構在DOM樹中保留,只改變列表節點的visibility屬性。如下:
<div>
<!-- 頭部 -->
<div class="header"></div>
<!-- 熱吧列表 -->
<list :style="{visibility: activeTab === 'HOT' ? 'visible' : 'hidden'}" class="hot-bar-list"></list>
<!-- 訂閱吧列表 -->
<list :style="{visibility: activeTab === 'SUBSCRIBED' ? 'visible' : 'hidden'}" class="subscribed-bar-list"></list>
</div>
1.3.2 客戶端支持
(1) 客戶端模塊
(2) 客戶端事件
1.3.3 Weex使用問題總結
- 如何處理本地圖片資源? Weex image組件不支持本地圖片,然而在項目開發過程中經常需要引入一些本地圖標文件,例如:
<image class="icon-map" :src="require('../assets/map.png')"/>
此時,可以在webpack配置文件里面配置url-loader,將圖片資源輸出到構建目錄。然后,通過output.publicPath配置項來配置資源的訪問路徑,在DEBUG模式下,將output.publicPath配置為本機server地址,在Production模式下,將output.publicPath配置為線上域名。由于圖標文件一般比較小,為了避免在無網絡狀態下渲染Weex頁面拉取不到線上圖標資源的情況,項目中將圖標文件直接用Base64編碼。url-loader的配置如下所示:
{
test: /\.(png|jpg)$/,
loader: 'url?limit=102400'
}
- 關于適配 Weex代碼中的高度和寬度的單位均為px,但是所設置的寬高并不是實際呈現出來的寬高,Weex框架在底層做了針對不同屏幕的適配工作,具體計算公式為 實際高寬 = 代碼高寬 * (屏幕寬度 / 750)。所以,在編寫界面的時候,最好以寬度為750的設計稿最為標準,否則需要根據計算公式對設計稿上標明的寬高做轉換。當需要設置元素的絕對寬高時,需要自行計算。計算時,需要獲取以下參數:
const screenWidth = this.$getConfig().env.deviceWidth; // 屏幕寬度
const scale = this.$getConfig().env.scale; // 屏幕倍率
- cell組件的appear事件和disappear事件在安卓端引發的性能問題 在熱吧列表,有一個打點需求,就是統計每一個吧Cell的展示時間。為了實現這個打點需求,對每一個吧Cell都監聽了appear事件和disappear事件。通過測試發現,當監聽了吧Cell的appear事件和disappear事件時,安卓端列表滾動不流暢,會出現明顯的卡頓現象。
- slider組件的點擊事件在安卓端不觸發 由于Weex提供的slider組件無法滿足使用要求,所以基于slider重新封裝了一個輪播圖組件,結構如下:
<div class="carousel">
<!-- 輪播圖 -->
<slider class="slider" auto-play="true">
<div class="item" v-for="item in items" @click="click">
<image class="cover" resize="cover" :src="item.cover"></image>
</div>
</slider>
<!-- 標題和輪播圖位置指示標志 -->
<div class="banner">
<text class="title"></text>
<div class="indicators">
<div :class="['indicator', current === i - 1 && 'selected-indicator']" v-for="i in items.length"></div>
</div>
</div>
</div>
輪播圖組件需要監聽點擊事件,當在slider組件或slider組件的父組件div上監聽點擊事件時,在安卓端點擊輪播圖并不觸發點擊事件。因此,需要在slider組件的子組件上監聽點擊事件。 在沒有設置loadmoreoffset時,list組件的loadmore事件在安卓端不觸發 雖然發現頁沒有loadmore邏輯,但是在使用weex的過程中對list組件進行了性能測試,使用到了list組件的loadmore功能,因此發現了list組件的loadmore事件在默認情況下不觸發的問題。只有顯示設置了loadmoreoffset且loadmoreoffset的值大于0時,list組件的loadmore事件才會觸發。
- cell組件的scope屬性 使list組件的時候,建議為同種類的cell設置相同的scope屬性。Weex內部會緩沖cell,每種類型的cell最多緩沖9個。如果不設置cell的scope屬性,weex會認為所有的cell的類型都不一樣,會緩沖所有的cell,導致內存占用大。
1.3.4 Weex實現效果
Weex實現的頁面操作體驗基本上接近原聲應用,列表滾動、TAB切換、頁面跳轉等都十分流暢。效果如下圖所示:
二、實踐總結
Weex可以選擇使用Vue作為開發框架,開發與調試體驗都比較好,接近Web開發體驗,但是使用上仍然存在一些問題,例如:
- CSS支持不夠完善,有些地方CSS樣式的在客戶端中的表現與WEB中的不太一致,甚至iOS和安卓端都會存在樣式表現的不一致。而且CSS不支持繼承,定義CSS樣式的時候無法引入變量,這樣在實現一些效果的時候十分不方便,例如白天模式和夜間模式;
- 文檔資料不夠完善;
- 某些內建組件存在使用上的BUG,例如slider組件在安卓手機上無法監聽click事件、list組件在沒有設置loadmoreoffset的情況下在安卓手機上不觸發loadmore事件;
當然,這些使用上的問題都可以解決或通過一定辦法去規避。Weex更值得我們關注的問題可能還是list組件的性能問題。在React Native的實踐中,我們深受長列表性能問題的困擾,而Weex號稱是一套可以構建高性能原聲應用的跨平臺方案,它在長列表的性能表現上如何呢?我們對此進行了測試和評估,發現Weex在長列表的性能表現上也并不樂觀。在列表長度不斷增長的時候,Weex的內存占用也是不斷增長的,在安卓和iOS上皆是如此。在iOS上,列表在不斷向下滾動的過程中,CPU使用率的表現也十分堪憂。以下兩張圖分別是在列表cell定高和變高下的測試結果【詳細測試結果請前往:RN & Weex ListView性能對比評估】:
因此,Weex目前可能更適用于非長列表的場景。由于其體驗接近原生應用,比H5要好,可以用于替換端內的一些H5頁面或一些需要頻繁變動的客戶端頁面。在這些方面Weex是否可規模投入使用尚待驗證,此次在內涵發現頁的使用正好可以觀察其穩定性。
來自:http://web.jobbole.com/92270/