好问题! +1
此问题与 FastClick 无关,但 FastClick 确实使您的问题的解决方案更加复杂。所以我会坚持纯 JavaScript 和原始触摸事件)
由于特定于平台的原因,在移动触摸设备上,webview 的实现与桌面 Web 浏览器有很大不同。
在这种情况下,一个重要的特性是 webview 中的动量滚动。
Momentum Scrolling 是设备的硬件加速功能。因此,当触摸屏幕上的可滚动区域时,硬件会识别该触摸并将 200 毫秒的倒计时计时器附加到可滚动区域,当触发时,该区域会进入硬件加速滚动状态。当硬件处于该状态时,它不会广播触摸事件,因为它们特定于硬件加速滚动。在提供的 200 毫秒内,可以通过在触摸事件上使用 preventDefault 来取消计时器并防止动量滚动。
这是我解决这个问题的方法。我假设您使用的是本机滚动,即overflow:scroll。
方法是将touchstart 事件附加到您想要触摸的元素。
一旦触发了touchstart 事件,事件处理程序就会将touchend、touchmove 和touchcancel 事件附加到目标元素。启动一个 setTimout 计时器,在 140 毫秒后删除新添加的事件。
以下是我的生产代码的一些剪辑:
我有两种用于从集合中添加和删除事件的事件方法:
var eventify = (function () {
function eventify(type, el, callback, phase) {
phase = phase || false;
if ((el.constructor.toString().contains('NodeList')) || (el.constructor.toString().contains('HTMLCollection'))) {
[].forEach.call(el, function (element) {
if (!element.hasEvent(type)) {
element.addEvent(type);
HTMLElement.prototype.addEventListener.apply(element, [type, callback, phase]);
}
});
} else {
if (!el.hasEvent(type)) {
el.addEvent(type);
HTMLElement.prototype.addEventListener.apply(el, [type, callback, phase]);
}
}
return callback;
}
return eventify
})();
var uneventify = (function () {
function uneventify(type, el, callback) {
if ((el.constructor.toString().contains('NodeList')) || (el.constructor.toString().contains('HTMLCollection'))) {
[].forEach.call(el, function (element) {
if (element.hasEvent(type)) {
element.removeEvent(type);
HTMLElement.prototype.removeEventListener.apply(element, [type, callback]);
}
});
} else {
if (el.hasEvent(type)) {
el.removeEvent(type);
HTMLElement.prototype.removeEventListener.apply(el, [type, callback]);
}
}
}
return uneventify
})();
然后我有一个用于滚动条上的点击事件的 tapify 方法:
var tapify = (function () {
function tapify(el, callback) {
eventify('touchstart', el, function (e) {
var that = this;
var start = e.pageY;
var target = e.target;
function dynamicEvents() {
var endfn = eventify('touchend', target, function (evt) {
e.preventDefault();
e.stopImmediatePropagation();
evt.preventDefault();
evt.stopImmediatePropagation();
uneventify('touchmove', target, movefn);
uneventify('touchend', target, endfn);
uneventify('touchcancel', target, cancelfn);
callback && callback(target);
});
var cancelfn = eventify('touchcancel', target, function (evt) {
e.preventDefault();
e.stopImmediatePropagation();
evt.preventDefault();
evt.stopImmediatePropagation();
uneventify('touchmove', target, movefn);
uneventify('touchend', target, endfn);
uneventify('touchcancel', target, cancelfn);
callback && callback(target);
});
var movefn = eventify('touchmove', target, function (evt) {
var distance = start - evt.pageY;
if (distance > 20) {
uneventify('touchend', target, endfn);
uneventify('touchcancel', target, cancelfn);
uneventify('touchmove', el, movefn);
}
});
setTimeout(function () {
uneventify('touchmove', target, movefn);
uneventify('touchend', target, endfn);
uneventify('touchcancel', target, cancelfn);
}, 140);
}
if (global.isIos) setTimeout(function () {
dynamicEvents();
}, 60);
else dynamicEvents();
}, false);
}
return tapify;
})();
我使用 global.isIos 来识别目标设备。 Android 在 200 毫秒后停止向 webview 发送触摸事件。
然后要将事件附加到一个元素或元素集合,请使用:
tapify(document.querySelectorAll('button'), function (e) {
//your event handler here!!
});
希望对你有帮助