首页 > 移动端的网页,怎么很好的把滑动事件和点击事件区别开?

移动端的网页,怎么很好的把滑动事件和点击事件区别开?

移动端的网页,比如各种新闻客户端,怎么很好的把滑动事件和点击事件区别开?


点击和滑动之间有一个本质的区别就是 touchmove(mousemove),在手机端,只需要判定是否触发这一点即可:


var flag = false;
var $selector = $('#selectorID');

 $selector.on('touchstart touchmove touchend', function(event) {
    switch(event.type) {
        case 'touchstart':
            falg = false;
            break;
        case 'touchmove':
            falg = true;
             break;
        case 'touchend':
            if( !falg ) {
                console.log('点击');
            } else {
                console.log('滑动');
            }
            break;
    }
});

不使用click,mouse之类的鼠标事件使用touch就行了。
阻止默认的事件


可以使用 Zepto 和 它的 touch 模块。

然后使用 tap 和 swipe swipeUp 之类的事件。

PS: jquery mobile 也有类似的事件。


活动事件是指?
点击事件尽量用touch,少用click。


以前寫過一個庫,研究過這一問題(當然產品環境下還是用現成的解決方案比較好)

也看過成熟解決方案的代碼

很簡單,記錄位移,任意方向超過 10 就不是 tap 了。

某一方向 超過 30 就是 swipe,如果在 swipe 之前豎直方向位移大於 10 就判定爲 scroll

如果進入 swipe 狀態,就 preventDefault

如果時間超過一個數值(具體多少忘了,好象是 750?)就不是 swipe 了,或者也可以直接觸發 swipe 事件。

只找到了更早的 touch 庫(剛開始 iOS 開發的時候寫的),部分代碼:

var Touchable = function() {

    function Touchable(target) {
        var self = this;

        function Touch(touch) {
            this.x = touch.pageX;
            this.y = touch.pageY;
        }

        EventEmitter.call(self);

        self.el = El.from(target);
        self.touches = {};

        attach(self, self.el);

        self.on({
            touchstart: function(e) {
                log("touchstart");
                // log(e);

                forEach(e.changedTouches, function(touch) {
                    capture(self, touch);

                    // log(touch);
                });

            }, 
            touchmove: function(e) {
                forEach(e.changedTouches, function(touch) {
                    var ot = self.touches[touch.identifier];

                    if (!ot)
                        return;

                    var t = new Touch(touch);

                    var dx = t.x - ot.x,
                        dy = t.y - ot.y;

                    if (ot.isSwipe === undefined && Math.abs(dy) > 10) {
                        ot.isSwipe = false;
                        ot.isScrolling = true;

                        self.emit("touchscrollstart", e);
                    } else if (ot.isSwipe === undefined && Math.abs(dy) < 10 && Math.abs(dx) > 30) {
                        e.preventDefault();

                        ot.isSwipe = true;
                    } else if (Math.abs(dy) > 30) {
                        ot.isSwipe = false;
                    }
                });
            },
            touchend: function(e) {
                log("touchend");
                // log(e);

                // log(self.touches);

                forEach(e.changedTouches, function(touch) {
                    var ot = self.touches[touch.identifier];

                    if (!ot)
                        return;

                    var t = new Touch(touch);

                    log(ot);
                    log(t);

                    var dx = t.x - ot.x,
                        dy = t.y - ot.y;

                    if (Math.abs(dx) < 10 && Math.abs(dy) < 10)
                        self.emit("touchtap", e);
                    else if (ot.isSwipe)
                        self.emit("touchswipe", e);
                    else if (ot.isScrolling)
                        self.emit("touchscrollend", e);

                    uncapture(self, touch);
                });

                // log(self.touches);
            },
            touchcancel: function(e) {
                log("touchcancel");
                // log(e);

                forEach(e.changedTouches, function(touch) {
                    uncapture(self, touch);

                    // log(touch);
                });
            }
        });



        function forEach(a, f) {
            Array.prototype.forEach.call(a, f);
        }

        function capture(self, touch) {
            var id = touch.identifier;

            var t = new Touch(touch);

            self.touches[id] = t;
        }

        function uncapture(self, touch) {
            var id = touch.identifier;

            delete self.touches[id];
        }
    }

    Touchable.prototype = Object.create(EventEmitter.prototype, Obj.descriptor({
        constructor: Touchable
    }));

    function attach(self, el) {
        "touchstart touchmove touchend touchcancel".split(" ").forEach(function(x) {
            self.el.on(x, function(e) {
                self.emit(x, e);
            });
        });
    }

    function setPush(set, element) {
        if (set.indexOf(element) === -1)
            set.push(element);
    }

    return Touchable;
}();    

舊代碼很爛,見諒。


自己的词焙应用也是有类似的需求, 并且更加复杂, 在上一版本的基础上重写了一个叫 Touch Delegate 的库 (TypeScript), 兼容 iOS (测试过 7), Android (测试过 4.x), WP8, 可以方便地区分各类触摸事件 (虽然内置的 Identifier 不多, 有其他需要可以自己添加). 最重要的是, 统一使用 Touch Delegate 管理触摸事件, 可以避免一些的问题, 比如父元素和子元素绑定了不同的触摸事件, 可能需要 stopPropagation/preventDefault, 但可能只想避免 tap 事件传递, 不想影响 slide.

不过现在还没有闲下来写文档, 简单说下用法 (bld 文件夹中有编译好的 JS 文件).

javascriptvar td = new TouchDelegate.Delegate('#item');
td.on(TouchDelegate.Identifier.tap, function (event) {
    console.log('tap');
    event.stopPropagation();
});

td.on(TouchDelegate.Identifier.hold, function (event) {
    console.log('hold');
    event.stopPropagation();
});

叫 Delegate 的原因是这些事件都是默认 delegate 到 document 上的. 不过这层 delegate 属于实现的细节, 在此基础上还可以再 delegate 一次.

javascriptvar td = new TouchDelegate.Delegate('#list');
td.delegate(TouchDelegate.Identifier.tap, '.item', function (event) {
    console.log(event.target);
    event.stopPropagation();
});

为了方便使用可以添加一个 shortcut 到 jQuery.fn.

javascriptjQuery.fn.tdTap = function (callback) {
    var td = new TouchDelegate.Delegate(this);

    td.on(TouchDelegate.Identifier.tap, function (event) {
        event.stopPropagation();
        callback();
    });

    return this;
};
【热门文章】
【热门文章】