MUI - 將tap模擬成原生click體驗

mui提供了tap事件替換了html5的click事件,解決了300ms延時的問題。不過相比原生app的click體驗仍是有些許差距的。關於300ms延時的問題,這篇帖子分析的比較完善,其中提到了穿透的問題,值得一讀
僅用微信爲例,只有當手指離開屏幕時才觸發click事件,若是對象綁定了長按事件,則觸發長按操做,離開時再也不觸發單擊事件。
這些邏輯不管是android, ios或者僅有1%的windows mobile都已經封裝好了,根本不用關心。html

那麼,咱們應該怎麼來實現呢?
下面是詳細的填坑歷程。。。。。。
html5

坑1.經過原生的touch來實現

//直接對dom添加touchend,這種方法只能針對位置不變且並無添加longtap事件的DOM有效
//若是在listview中,你上下滑動,那就歇菜了。
//那麼天然而然就想到了touch.target的位移,並作出判斷是下滑仍是單擊。
//本身去寫複雜度、代碼量估計會很可觀。
//所以就想到了了在原有的框架代碼上去實現。
//下面就到了坑2
document.getElementById("").('touchend', function() {
    //
});

坑2.更改mui.gestures.tap.js

坑2.1 自定義事件偵聽機制

mui沒有提供相似於jq.data('events')獲取事件列表的機制,另外官方也推薦使用addEventListener去綁定事件。
我要去獲取當前DOM的事件列表應該怎麼作呢?android

你問我問毛要去獲取DOM的事件列表,,,
呵呵,我總要知道DOM有木有綁定longtap事件好作規避吧ios

csdn的這個帖子看似有用
http://bbs.csdn.net/topics/390250552git

function addEvent(dom,type,fn) {
    if(document.addEventListener) {
        dom.addEventListener(type, fn, false);
    } else if(document.attachEvent) {
        dom.attachEvent('on' + type, fn);
    } else {
        dom['on' + type] = fn;
    };
    dom["Listener-"+type]=!0;
}

實際上並無什麼卵用
思想是好的.....
我總不能每次addEventListener都去調一下這個方法吧!github

坑2.2 使用getEventListeners

找啊找,終於找到了getEventListeners()這個全局方法,在chrome和safari控制檯中測試都木有問題。
喜出望外......
這下終於能解決問題了
因而有了如下的方法chrome

var getEvents = function(obj) {
        console.log(getEventListeners(obj));
        return typeof(getEventListeners) == "function" && getEventListeners(obj);
    }
    var hasEventype = function(obj, e) {
        var es = getEvents(obj);
        console.log(es[e]);
        return es && !!es[e];
    }

調用下試試windows

if (!hasEventype(target, 'longtap')) {}

報錯
getEventListeners is undefined微信

R U kidding?!!!!session

你丫在逗我.............

我瞬間感覺到了深深地惡意

原來這個方法只能在控制檯中用,
呵呵,人艱不拆......

坑2.3 使用全局變量規避

給mui添加一個全局變量isLongTapAtived,看變量名就知道什麼意思吧
mui.gestures.longtap.js中初始化,在handle中激活

(function($, name) {
    $.isLongTapAtived = false;//初始化
    var timer;
    var handle = function(event, touch) {
        switch (event.type) {
            case $.EVENT_START:
                clearTimeout(timer);
                timer = setTimeout(function() {
                    $.trigger(session.target, name, touch);
                    //激活了
                    $.isLongTapAtived = true;
                }, options.holdTimeout);
                break;
        }
    };

    });
})(mui, 'longtap');

mui.gestures.tap.js中判斷有無激活

var handle = function(event, touch) {
        var session = $.gestures.session;
        var options = this.options;
        switch (event.type) {
            case $.EVENT_END:
                //......
                if (touch.distance < options.tapMaxDistance) {
                    if (touch.deltaTime < options.tapMaxTime) {
                        //.....
                    } else {
                        //若是當前對象添加了長按偵聽,略過,不然仍然視爲tap事件
                        //if (!hasEventype(target, 'longtap')) {
                        if (!$.isLongTapAtived) {
                            //若是沒有longtap事件,離開屏幕是觸發tap事件
                            $.trigger(target, name, touch);
                        }
                        //重置
                        $.isLongTapAtived = false;
                    }
                }
                break;
        }
    };

想法是美好的,現實是他麼殘酷的。不管有無longtap事件,都要走一遍longtaphandle代碼
因而 $.isLongTapAtived === true;
因而 永遠trigger tap 事件

呵呵,想死的心都有了


路子看來是走對了,可是應該怎麼作???

終極解決方案

mui.isLongTapAtived依然添加,只是在每一次DOM添加的longtap事件內激活

document.querySelector("#").addEventListener('longtap',function(){
    mui.isLongTapAtived=true;
    console.log('你觸發了longtap事件');
});

這樣對開發者是不友好的,不過暫時沒辦法,只能如此取捨了

代碼已提交至https://github.com/phillyx/mui/ 並推送給官方

相關文章
相關標籤/搜索