參照了官網(wǎng),新手一般都會(huì)知道react native 的點(diǎn)擊事件是靠touch*系列組件內(nèi)部嵌套其它組件來(lái)完成的,touch系列組件主要提供3個(gè)跟觸摸有關(guān)系的方法,onpress ,onpressin,onpressout,onLongPress,主要是繼承了TouchableWithoutFeedback組件,由于我這里指講干貨,基礎(chǔ)部分大家可以去官網(wǎng)文檔詳細(xì)查看一下支持哪些方法:http://reactnative.cn/docs/0.28/touchablewithoutfeedback.html#props
現(xiàn)在我們來(lái)說(shuō)說(shuō)我遇到的第一個(gè)坑:
這是想實(shí)現(xiàn)一個(gè)原生上非常簡(jiǎn)單的功能:點(diǎn)擊空白處***,點(diǎn)擊空白的時(shí)候做一些事情。APP上界面的絕大部分都是被一個(gè)listview占據(jù)的,顯然就想到了點(diǎn)擊空白===點(diǎn)擊listview,果斷的,給listview套上了一個(gè)toch**組件,寫(xiě)了onpress方法,卻沒(méi)想到在這里埋下了一個(gè)巨坑。
一開(kāi)始并沒(méi)什么問(wèn)題,效果非常好,響應(yīng)正常,可是在快到下班的時(shí)候發(fā)現(xiàn),listview突然不能滾動(dòng)了,又測(cè)試了幾次,一會(huì)可以滾,一會(huì)不可以滾,可以滾的概率低于1/10...........呵呵,又是一個(gè)加班的夜晚。當(dāng)然很快的我發(fā)現(xiàn)是touch**組件的問(wèn)題。把touch**組件去了之后一切正常了~~但是PM那邊一定要這個(gè)點(diǎn)擊空白的需求.......看來(lái)今晚又不用下班了。無(wú)奈仔細(xì)翻看文檔,最后看到了手勢(shì):http://reactnative.cn/docs/0.28/gesture-responder-system.html#content
在了解了RN的事件攔截機(jī)制之后,我想到了就只攔截press事件,move事件就留給listview滾動(dòng)用,然后就是照文檔很快的敲定了:
主要的幾個(gè)方法:onStartShouldSetResponderCapture: (evt) => true,(開(kāi)始攔截事件)
onMoveShouldSetResponderCapture: (evt) => false,(由于不需要攔截move事件,所以這里返回false)
onResponderGrant: (evt) => {}:申請(qǐng)成功,組件成為了事件處理響應(yīng)者,這時(shí)組件就開(kāi)始接收后序的觸摸事件輸入。
onResponderReject: (evt) => {}:申請(qǐng)失敗了,這說(shuō)明其他組件正在進(jìn)行事件響應(yīng),并且它不想停止事件響應(yīng),so你的申請(qǐng)被拒絕了,后續(xù)輸入事件不會(huì)傳遞給本組件進(jìn)行處理。
onResponderStart: (evt) => {}:手指按下的回調(diào);
onResponderMove: (evt) => {}:觸摸手指移動(dòng)的事件,這個(gè)回調(diào)親測(cè)大概一秒響應(yīng)1-2次,so,這里一定要處理好。
onResponderRelease: (evt) => {}:抬起手指的回調(diào),表示用戶(hù)完成了本次的觸摸交互。這以后,組件不再響應(yīng)事件,組件取消激活。(這里有坑)
onResponderEnd: (evt) => {}:組件結(jié)束事件響應(yīng)的回調(diào)。
onResponderTerminationRequest: (evt) => bool :當(dāng)其他組件申請(qǐng)成為響應(yīng)者的時(shí)候,是否放權(quán)。
更多細(xì)節(jié)請(qǐng)參考;http://www.race604.com/react-native-touch-event/ ?這篇文章作者寫(xiě)得非常清楚。我們這里主要講如何搞定這些坑。
根據(jù)官方例子,是把這些方法組成一個(gè)對(duì)象:
this._panResponder = PanResponder.create({onStartShouldSetResponderCapture:()=> true,
.......})
再作為view的一個(gè)屬性傳進(jìn)去:
<View ? {...this._Responder.Handlers} />
我把要在點(diǎn)擊空白時(shí)執(zhí)行的方法寫(xiě)在了一開(kāi)始的onResponderStart,測(cè)試了幾次,效果不錯(cuò),看來(lái)今晚還來(lái)得及回去睡覺(jué)。就在我做最后幾次測(cè)試打算下班的時(shí)候,他慢慢的就開(kāi)始不行了,一個(gè)天坑再次出現(xiàn),不可以滾的概率越來(lái)越大,大概在70-80%,雖然比剛剛好了點(diǎn),但是仍然遠(yuǎn)遠(yuǎn)超出忍受范圍。我就開(kāi)始嘗試改變事件攔截和事件執(zhí)行的邏輯,在整個(gè)響應(yīng)過(guò)程的每一個(gè)部分都測(cè)試過(guò),完全沒(méi)有什么卵用,不滾就是不滾!??!打印日志跟蹤(由于用了realm那個(gè)坑比數(shù)據(jù)庫(kù)跟VScode的bug導(dǎo)致我不能斷點(diǎn)調(diào)試,整個(gè)項(xiàng)目到結(jié)束都只能日志跟蹤,結(jié)果最后項(xiàng)目里到處都是console.log,簡(jiǎn)直淚奔)發(fā)現(xiàn)可以滾動(dòng)的時(shí)候是觸發(fā)了這個(gè)方法onResponderTerminationRequest,系統(tǒng)強(qiáng)制奪權(quán)了??磥?lái)情況已經(jīng)明了onResponderRelease這個(gè)事件之后并不是組件不再響應(yīng),取消激活,而僅僅是抬起手指而已。
現(xiàn)在明了,我就在需要的時(shí)候注冊(cè)事件,操作完成之后把這個(gè)事件攔截注銷(xiāo)就好了,機(jī)制如我,嘿嘿!主要就是控制onStartShouldSetResponderCapture這個(gè)方法返回true or false 而已。很快的就改好了觸發(fā)邏輯,測(cè)了好幾次之后發(fā)現(xiàn)有點(diǎn)不對(duì)勁,一會(huì)好使,一會(huì)不好使的。仔細(xì)看日志輸出,發(fā)現(xiàn)貌似要setState之后才有用,仔細(xì)一想,既然是作為view的內(nèi)部屬性對(duì)象,本身改變之后當(dāng)然要重新render才能生效,想到這里真是為自己的智商拙計(jì)。
在每次注冊(cè)和注銷(xiāo)之后setstate,果然,測(cè)試了N次,完美~~ ? ? ? 然而,我還是高興的太早了.........
點(diǎn)擊空白,這個(gè)空白之處肯定是占據(jù)頁(yè)面比重最大的地方,而我卻在頻繁的render這個(gè)重量級(jí)的組件,以react native這種渣性能來(lái)說(shuō),估計(jì)會(huì)讓系統(tǒng)爆掉!果然,每次響應(yīng)都有將近1.5秒的延遲(測(cè)試版幾乎0數(shù)據(jù)),再次為自己的智商拙計(jì)........
再次看文檔,看例子,查資料,看源碼..............
然后有了驚天發(fā)現(xiàn):

敢情官網(wǎng)的那個(gè)例子是坑我呢!這些方法直接就可以使用。但是仔細(xì)一看,這些方法跟我剛剛寫(xiě)的不是一樣的?只是調(diào)用方式發(fā)生了改變??但是他既然在這里給出來(lái)了,那他是否已經(jīng)把內(nèi)部邏輯做了完美的處理,不會(huì)再發(fā)生事件奪權(quán)和事件沖突,響應(yīng)結(jié)束能系統(tǒng)自動(dòng)解除攔截??本來(lái)這些東西是應(yīng)該相信RN作者已經(jīng)做好了的,但是由于踩坑太多,所以我在這里是持懷疑的態(tài)度。死馬當(dāng)活馬醫(yī)吧!這個(gè)邏輯更簡(jiǎn)單,減少了我1-200行代碼,最后測(cè)試,沒(méi)有什么異常........
.看了一眼時(shí)間,凌晨4點(diǎn)了,是回去睡覺(jué)還是不回呢?這根本就不是一個(gè)值得糾結(jié)的問(wèn)題
第二天了,還是沒(méi)什么異常.....
這個(gè)坑應(yīng)該算是,總算是填上了吧??!
如果大家有更好的解決辦法請(qǐng)?jiān)谙旅媪粞裕浅8兄x
最后吐槽一句,react確實(shí)不錯(cuò),react native確實(shí)不怎么樣~~
(陰謀論:RN這種渣性能和套用前端的渣邏輯,肯定又是軟件提供商伙同硬件提供商倒逼消費(fèi)者升級(jí)硬件的典型陰謀!)