前言
三月初,阿里巴巴開源的一套基于 Weex、React Native 的富交互解決方案 「BindingX」。提供了一種稱之為 「Expression Binding」 的機制可以在 Weex、React Native 上讓手勢等復(fù)雜交互操作以60fps的幀率流暢執(zhí)行,而不會導(dǎo)致卡頓,因而帶來了更優(yōu)秀的用戶體驗。
背景
聽上去「高大上」,那為啥要造這個輪子呢?
這就得從源頭說起,他到底解決了什么問題。
我們知道,Weex 和 React Native 同樣都是三層結(jié)構(gòu),「 JS 層、 Native 層、 Bridge 層」,Native 層負(fù)責(zé)視覺繪制、事件收集,JS 層負(fù)責(zé)視覺控制、事件處理,Bridge 層是 JS 層和 Native 層的溝通橋梁,負(fù)責(zé)指令「翻譯」。以 Weex 為例:
想讓 Native 層做一些復(fù)雜的交互操作時,JS 層就需要不停得處理從 Native 層收集來的事件然后作出「及時」響應(yīng),如果響應(yīng)「不及時」就會導(dǎo)致視覺卡頓。
怎么樣才算是「及時」呢?
我們常說 60fps 幀率是流暢的基礎(chǔ),這就意味著,一次有效的刷新需要在 1/60 s 內(nèi)完成,如果 JS 層從事件接受、處理、回饋到 Native 繪制新的視圖完成超過了 16.67ms 將會出現(xiàn)「視覺卡頓」。
另外,即使每一次更新都可以完全控制在 16.67ms 內(nèi),大量的通訊操作也會消耗掉過多的 CPU,以至于加大了 Crash 的風(fēng)險
如果不突破這層瓶頸,此類技術(shù)將很難達(dá)到一個新的高度。
BindingX 就是解決這個問題的。
原理
BindingX 提出的 「Expression Binding」 將具體的手勢控制行為以 「表達(dá)式」 的方式傳遞給 Native,監(jiān)控「被綁定元素」上發(fā)生的手勢操作并輸出過程中橫向「x」和縱向「y」的偏移量,因此我們即可將「x,y」作為表達(dá)式「f(x),f(y)」的入?yún)ⅲ槍π缘膶δ骋荒繕?biāo)元素的樣式進(jìn)行「綁定變化」。
而這所以操作都是在 Native 層獨立完成的,大大減小了 JS 層和 Bridge 層的壓力。
「無 Binding 模式」
「Binding 模式」
表達(dá)式
表達(dá)式,是由數(shù)字、運算符、變量等以能求得有意義數(shù)值的字符串。譬如, x\*3+10
就是一個表達(dá)式,當(dāng)x被賦值時,整個表達(dá)式就會有一個明確的結(jié)果。通過表達(dá)式,我們就可以描述一個具體的交互行為,比如我們希望x從0變化到100時,透明度能從1變化到0.5,那么表達(dá)式可以描述為: f(alpha) = 1-(x/100)*0.5
也可以是 f(alpha) = 1-x/200
只不過第一種表達(dá)式更直白。
下面舉一個簡單的例子。
/* 簡碼 */
bindingx.bind({
anchor:foo_view.ref , //==> 事件的觸發(fā)者
eventType:'pan', //==> 事件類型
props: [
{
element:foo_view.ref, //==> 要改變的視圖的引用或者id
property:'transform.translateX', //==> 要改變的屬性
expression:'x+0' //==> 表達(dá)式
}
]
});
就這么簡單,幾行代碼即可綁定 foo_view
實現(xiàn)視圖隨手勢移動的交互。當(dāng)然復(fù)雜的也有,只不過都是由這么一個個小的交互堆積而成的。
除了基本的四則運算外,還支持三元運算符、數(shù)學(xué)函數(shù)等高級語法,基本可以滿足絕大部分的場景。
事件類型
前面的例子中用到了 pan
手勢,除手勢外,BindingX 還支持「列表的滾動 scroll
」、「動畫 timing
」甚至是「陀螺儀感 orientation
」,每種事件類型使用方式大致相同,也有注意點,詳細(xì)請參閱《bindingx 官方文檔》。
Do it
怎么樣能快速體驗?zāi)兀?/p>
跟上我的腳步
playground
官方雖然也提供了 試驗田 https://alibaba.github.io/bindingx/playground,但語法均為 Rax 但 DSL,并不少 Weex 對外的 Vue 版本,我們無法在線編輯查看效果,只能使用阿里系A(chǔ)pp「如淘寶、閑魚、飛豬」掃碼體驗效果。
這些都不是我們想要的。
當(dāng)然方法總是有的。
直接將 BindingX 的官方代碼 clone
下來,上面有支持 Vue 版本的 Weex Playground。
bindingx/weex/playground/[ios|android]
ios 和 android 選一個用工具安裝到自己的手機上。此處就不多解釋了,不會的問下 google,或者下方留言。
使用 http://dotwe.org/vue/ 在線編輯,掃碼看效果。
給大家分享幾個 Vue 版本的 demo。
http://dotwe.org/vue/e50f76a6c13337b6fa4201a045c5dc0c
http://dotwe.org/vue/2dff486956044ea59b3d38a2cf20b506
http://dotwe.org/vue/64998432f2a249f5cb35b4de0040526d
http://dotwe.org/vue/cd942c4bee9c4b7bcceda4e3aaf94c70
嚴(yán)選 demo 引入 BindingX
這是很早以前的一個小 Demo,感興趣的可以 star 一下
https://github.com/zwwill/yanxuan-weex-demo
下面我基于嚴(yán)選的 Demo 進(jìn)行的小試用。
升級 ios platform
要想使用 BindingX 插件,就必須使自己的 platform 支持。方法很簡單,只需要將 platforms/ios/Podfile
進(jìn)行升級修改即可。
source 'git@github.com/CocoaPods/Specs.git'
platform :ios, '8.0' #最低8.0
#inhibit_all_warnings!
def common
pod 'WeexSDK', '0.17.0' #升級至 0.17.0
pod 'Weexplugin', :path=>'./Weexplugin/'
pod 'WXDevtool'
pod 'SDWebImage', '3.7.5'
pod 'SocketRocket', '0.4.2'
pod 'BindingX' #增加 BindingX
end
target 'WeexDemo' do
common
end
target 'WeexUITestDemo' do
common
end
隨后執(zhí)行一遍 pod install
即可安裝成功。如出現(xiàn)錯誤提示,按提示 fix 掉即可。
小試牛刀
Vue 的引入方式不同于 Rax,需要使用 weex.requireModule()
API。
<template>
<div class="wrapper">
<image ref="headerBg" resize="cover" src="http://cdn.zwwill.com/yanxuan/imgs/bg5.png"></image>
<scroller ref="contentScroller">
<div>
<!-- 省略非關(guān)鍵代碼 -->
</div>
<div class="fbs">
<!-- 省略非關(guān)鍵代碼 -->
</div>
</scroller>
</div>
</template>
<script>
const binding = weex.requireModule('bindingx'); //引入 bindingx
export default {
mounted(){
this.headerBgBinding();
},
beforeDestroy(){
this.headerBgBindingDestory();
},
methods: {
headerBgBinding(){
let self = this,
scroller = self.$refs.contentScroller.ref,
headerBg = self.$refs.headerBg.ref;
let bindingResult = binding && binding.bind({
eventType:'scroll',
anchor:scroller,
props:[
{
element:headerBg,
property:'transform.scale',
expression:{
origin:'y<0?(1-y/500):(1+y/500)'
}
},
{
element:headerBg,
property:'transform.translateY',
expression:{
origin:'-y/2'
}
}
]
},function(e){
});
self.gesToken = bindingResult.token;
}
headerBgBindingDestory(){
let self = this;
if(self.gesToken != 0) {
binding.unbind({
eventType:'scroll',
token:self.gesToken
})
self.gesToken = 0;
}
}
}
}
</script>
實現(xiàn)的效果就是最常見的個人信息頁,title 背景隨著滾動事件變換大小。
效果動圖 http://cdn.zwwill.com/yanxuan/resource/bindingx2.gif
寫在最后
Weex 有了 BindingX 如虎添翼。效率更高性!能更穩(wěn)定!同期開源的還有 GCanvas 也是一把神器。
近期工作繁重,通宵寫文章,如發(fā)現(xiàn)文章殘瑕處,敬請諒解!
相關(guān)鏈接
- https://github.com/zwwill/yanxuan-weex-demo
- https://alibaba.github.io/bindingx/
- http://dotwe.org/vue/e50f76a6c13337b6fa4201a045c5dc0c
- http://dotwe.org/vue/2dff486956044ea59b3d38a2cf20b506
- http://dotwe.org/vue/64998432f2a249f5cb35b4de0040526d
- http://dotwe.org/vue/cd942c4bee9c4b7bcceda4e3aaf94c70
作者: 木羽 zwwill
首發(fā)地址:https://github.com/zwwill/blog/issues/20