在使用交互式DOM元素的单页Javascript应用程序中,我发现“mouseover-mousemove-mousedown-mouseup-click
”序列发生在之后“touchstart-touchmove-touchend
”序列中事件。
我还发现,在 mouse*-click
事件期间执行“event.preventDefault()
”可以防止“touchstart
”事件发生,但仅,而不是touchmove
和touchend
期间。这是一个奇怪的设计,因为在touchstart
期间无法知道用户是想要拖动还是滑动还是只是点击/点击该项目。
我最终设置了一个与时间戳相关的“ignore_next_click”标志,但这显然不是很干净。
有没有人知道更好的方法,或者我们错过了什么?
请注意,虽然“点击”可以被识别为“touchstart-touchend
”序列(即没有“touchmove
”),但是某些事情,例如键盘输入焦点,只能发生在适当的click
事件中。
答案 0 :(得分:4)
我遇到了制作跨平台HTML5 / JS应用程序的类似问题。对我来说唯一真正的答案是 preventDefault 触摸事件,并根据我的逻辑实际管理触摸状态并点击我自己的点击,拖动等事件。这听起来比实际上更令人生畏,但模仿的点击/鼠标事件在大多数移动浏览器上都能完美运行。
点击,额外的鼠标序列就是为了您的方便(和兼容性)。我的经验法则 - 如果它是为了您的方便,但它不方便,最好杀死它。
就输入框而言,它们只需要touchend事件。我已经杀死了点击/鼠标事件,仍然可以让移动浏览器正确响应输入的触摸。如果它仍然给你带来问题,你可以修改事件处理程序以仅抑制非输入事件:
function touchHandler(event) {
var shouldIgnore = event.target != null
&& ( event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea" );
if(!shouldIgnore) e.preventDefault();
}
答案 1 :(得分:3)
我自己已经找到了解决方案,因为我在其他地方找不到足够的解决方案:
var isTouch = ('ontouchstart' in window);
function kill(type){
window.document.body.addEventListener(type, function(e){
e.preventDefault();
e.stopPropagation();
return false;
}, true);
}
if( isTouch ){
kill('mousedown');
kill('mouseup');
kill('click');
kill('mousemove');
}
检查isTouch
可让鼠标输入设备正常工作,但会杀死Safari / iOS上的模拟事件。诀窍是在useCapture = true
的调用中使用addEventListener
,这样我们就可以挖掘页面中的所有鼠标事件,而无需在整个Web应用程序中破解代码。请参阅此处的函数文档:https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener
编辑:
既然用于处理此问题的库更好,您可以使用类似Fastclick的替代方法(https://github.com/ftlabs/fastclick)。
答案 2 :(得分:2)
如果您必须支持同时支持鼠标和触摸的设备,另一种解决方案是使用捕获事件监听器来停止发生的所有鼠标事件
触摸事件的信息(时间,位置或目标元素)可以记录在另一个捕获事件监听器中。
答案 3 :(得分:1)
在Window.matchesMedia函数中包装仅鼠标代码是我找到的最简洁的方法。
if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) {
el.addEventListener('mouseover', ev => {
// mouse handler, no simulated hover
}
}
这可用于防止模拟悬停,但也可能会阻止模拟点击。
注意:从版本58开始,Firefox上需要-moz-touch-enabled部分。
答案 4 :(得分:1)
只需防止touchend
事件。当您触摸元素时,它将允许浏览器滚动页面,但不会使其发出人为的鼠标事件。
element.addEventListener('touchend', event => {
event.preventDefault();
});
答案 5 :(得分:0)
Creating Fast Buttons for Mobile Web Applications有解决问题的方法。
还要注意,当使用IE10时,preventDefault()不会在MSPointerDown事件之后停止ghost /合成/模拟鼠标事件,因此真正的跨浏览器解决方案更难。
答案 6 :(得分:0)
此解决方案使您可以侦听PointerEvents
(如果存在),然后侦听TouchEvents
(如果存在),然后侦听MouseEvents
(如果另外两个都不存在)。移动Safari仍会同时提高touchstart
和mousedown
,但您只会听touchstart
。
if (window.PointerEvent) { /* decent browsers */
etouch.addEventListener('pointerdown', (e) => {
console.log('pointerdown');
});
}
else if (window.TouchEvent) { /* mobile Safari */
etouch.addEventListener('touchstart', (e) => {
console.log('touchstart');
});
}
else { /* desktop Safari */
etouch.addEventListener('mousedown', (e) => {
console.log('mousedown');
});
}
答案 7 :(得分:0)
当设备支持触摸事件时,您可以尝试在“ click”,“ mousedown”或“ mouseup”事件上退出该功能。
use.addEventListener("click",function(e){
// EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
if ("ontouchstart" in document.documentElement) return false;
// YOURMOUSEONLY CODE HERE
});
答案 8 :(得分:0)
在当前的浏览器上,使用'pointerwhatever'
代替'mousewhatever'
似乎可以正常使用(2019)。
即他们发明了way,其中所有的入门设备都具有相同的代码。
答案 9 :(得分:0)
向touchstart添加事件侦听器,该事件侦听器将数据接触的属性添加到元素。添加另一个事件侦听器以单击以检查是否涉及数据。如果存在,请阻止默认设置并将其删除。这是我实现中的一些JS。
var menuLinks = document.querySelectorAll('#my-nav>li>a');
for (var i = 0; i < menuLinks.length; i++) {
var menuLink = menuLinks[i];
menuLink.addEventListener('touchstart', function () {
menuLink.setAttribute('data-touched', '');
});
menuLink.addEventListener('click', function (event) {
if (menuLink.hasAttribute('data-touched')) {
menuLink.removeAttribute('data-touched');
event.preventDefault();
}
});