Weex布局尺寸通用適配方案的研究
問題
weex為前端賦予了強大的跨端開發能力和較一致的良好的用戶體驗。weex一般是與native進行協作開發:
- 同app內不同頁麵用兩者分別開發,統一串聯
- 同頁麵兩者協作開發,比如native提供組件,weex使用
由於native布局一般采用定高不定寬的方式,以求不同尺寸的屏幕可以得到基本一致的布局體驗,然而weex布局采用基於750的等比例縮放,這種不一致導致的問題:
- 同一元素在不同屏幕的尺寸展現不一致,大屏手機尺寸偏大,小屏手機尺寸偏小
- 與native尺寸偏差較多
字號的差異也比較明顯。
默認依據ip6尺寸布局,慘不忍睹的現場直擊...
- 紅框部分的滑動組件是native的,而背景容器是weex布局的,由於weex等比例縮放,而native使用pt,導致iphone 5s native組件溢出,而iphone 6p組件相比於容器過小。
- 下麵是iphone 6p下native列表和weex列表字號對比
思考及分析
weex目前的尺寸處理方式:
無視屏幕分辨率和尺寸,虛擬寬度統一為750,布局尺寸以750為基準按比例縮放。
那麼使用weex原生尺寸定義想實現native的體驗“在不同尺寸手機上同樣元素的尺寸基本一致”是不太可能的。
不過weex在Js運行時提供了屏幕的物理分辨率和像素比例,那麼運行時可不可以用js動態算一下呢?
我們定義weex的原生尺寸為vp(virtual pixel),視覺稿的尺寸或native的尺寸為ns(native size)。
期待的轉換規則為
這樣用戶隻需要按native的方式寫布局尺寸,就可以映射為weex的尺寸,被weex布局邏輯動態解析,從而達到我們的目的。
既然我們要模擬Native的尺寸適配,首先要知己知彼,簡單了解了一下native的適配方法
安卓尺寸適配
安卓提供了一個萬能的適配單位:dp,dp屏蔽了屏幕大小和分辨率,提供了一致體驗,dp和物理像素的換算關係如下:
欲轉換先取dpi,可惜weex沒有dpi,但提供了一個比例scale,可用來計算dpi
換算可得
IOS尺寸適配
類似dp的單位是著色器(似乎等同於pt?)
換算可得
通過分析我們發現,安卓和IOS的適配規則殊途同歸,可統一轉換規則為:
function translateRule(dp) {
return dp * 750 / ( deviceWidth / scale );
}
到這裏似乎大功告成,隻要在寫樣式時祭出我們的法寶:計算屬性,並動態賦到模板節點的style屬性上即可。然而這種方式讓開發同學想起了前端茹毛飲血的上古時代,而今前端顯然已經沐浴在現代化的春風裏很久了。如果在寫樣式的時候需要寫固定尺寸時,能像native一樣直接寫pt/dp這樣的單位那肯定是極好的。
掃了一下經過weex-loader編譯的代碼,與vue-loader編譯的區別主要是在style的處理上,前者將style編譯為map形式,並掛載到Vue實例上,所以我們在兩個位置可以拿到編譯後的style map
- vue實例生命周期內
- vue導出的組件對象上
由此有兩個插入自動處理尺寸邏輯的方案:
- 運行時。於上述2的位置,掃描vue實例的style map,過濾出自定義單位和值並替換為weex識別的尺寸
- 編譯時。通過webpack loader對vue文件進行預處理,掃描自定義單位並於1位置注入運行時處理尺寸的邏輯
分析
方案一:
- 性能較差,需要遍曆每個頁麵整個組件樹的style map
- vue實例拿到的style map,已被weex-loader過濾掉自定義單位,變成了人畜無害的數字。。。
- 需要js代碼處理,一看就不是weex的親兒子單位
結論:放棄
方案二:
- 每個組件單獨注入修改尺寸的代碼,免去了遍曆組件樹的開銷
- 在weex-loader的樣式分析之前解析,可以拿到原始樣式代碼
- 純編譯時純工具處理,使用自定義單位如同使用原生單位一樣方便,weex開發者毫無感知
結論:靠譜
實現
主流程
- 識別style裏的自定義單位/函數,抽取單位前的數值
- 根據規則生成尺寸處理邏輯的代碼
- 注入到vue實例的beforeCreate函數裏
樣式識別支持less和css
單位一般用於單參數映射規則,多參數映射規則可寫成函數
規則文件
基於以下原因,需要獨立的、用戶自定義的、vue實例裏可以方便引用的規則文件
- 可能需要多個單位,因此需要一個規則集合
- 規則需要支持自定義,方便使用者修改和擴展
- 用戶可能也需要手動調用某個單位的計算規則,比如實現動畫
loader實現內部提供了一個默認的規則文件,支持用戶自定義規則文件去覆蓋和擴展默認規則
默認規則
單位/函數 | 描述 |
---|---|
dp | 模擬安卓dp單位, 兼容ios,與native布局尺寸相同 |
mq | media query |
vw | 相對於屏幕寬度的百分比 |
vh | 相對於屏幕高度的百分比 |
數據流圖如下:
效果
無痛使用
.class-name {
/*
自定義單位/處理函數dp, vw
多個參數可用函數形式,單參數建議用單位
*/
width: 100dp;
height: 200vw;
font-size: dp(24, 750); //可直接用24dp,這裏僅做例子
}
UI效果
- 不同尺寸屏幕native組件和weex容器完美契合(貼圖不是實際屏幕大小,所以5s布局尺寸看著比較大,僅做頁麵內native和weex的尺寸比較)
- weex與native文字尺寸基本一致(由於weex安卓使用小數字號有問題,所以計算後的字號做了四舍五入取整,且字體也差異,所以效果還是稍微有點差異,但對比做適配前已經好很多了)
擴展
因為實現原理是編譯時解析自定義樣式函數,並插入運行時js代碼。因此除了用於計算尺寸外,還可以計算其他依賴環境(比如屏幕尺寸、設備類型等)的樣式,成為一個通用的weex css運行時處理工具。
當然更期待著weex原生支持各種布局單位,這才是康莊大道。
包地址:https://web.npm.alibaba-inc.com/package/@ali/weex-css-runtime-loader
最後更新:2017-07-19 20:03:08