[英]Preventing mouse emulation events (i.e. click) from touch events in Mobile Safari / iPhone using Javascript
在使用交互式 DOM 元素执行单页 Javascript 应用程序时,我发现“ mouseover-mousemove-mousedown-mouseup-click
”序列在“ touchstart-touchmove-touchend
”事件序列之后全部发生。
我还发现,可以通过在touchstart
事件期间执行“ event.preventDefault()
”来防止“ mouse*-click
”事件发生,但只有这样,而不是在touchmove
和touchend
期间。 这是一个奇怪的设计,因为在touchstart
期间还无法知道用户是否打算拖动或滑动或只是点击/单击项目。
我最终在某个与时间戳相关的地方设置了一个“ignore_next_click”标志,但这显然不是很干净。
有没有人知道这样做的更好方法,或者我们错过了什么?
请注意,虽然“点击”可以被识别为“ touchstart-touchend
”序列(即没有“ touchmove
”),但有些事情,例如键盘输入焦点,只能在正确的click
事件期间发生。
只需防止touchend
事件。 当您触摸元素时,它会让浏览器滚动页面,但不会让它发出人工鼠标事件。
element.addEventListener('touchend', event => {
event.preventDefault();
});
我在制作跨平台 HTML5/JS 应用程序时遇到了类似的问题。 对我来说唯一真正的答案是在触摸事件上防止默认,并根据我的逻辑实际管理触摸状态和触发点击、拖动等事件。 这听起来比实际更令人生畏,但模仿的点击/鼠标事件在大多数移动浏览器上都能完美运行。
单击和额外的鼠标序列都是为了您的方便(和兼容性)。 我的经验法则 - 如果它是为了您的方便但不方便,最好杀死它。
至于输入框,他们只需要 touchend 事件。 我已经杀死了点击/鼠标事件,并且仍然能够让移动浏览器正确响应输入的触摸。 如果它仍然给您带来问题,您可以修改事件处理程序以仅抑制非输入事件:
function touchHandler(event) {
var shouldIgnore = event.target != null
&& ( event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea" );
if(!shouldIgnore) e.preventDefault();
}
我自己做了一个解决方案,因为我在其他地方没有找到足够的解决方案:
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 上的模拟事件。 诀窍是在对addEventListener
的调用中使用useCapture = true
,这样我们就可以获取页面中的所有鼠标事件,而无需破解整个网络应用程序的代码。 在此处查看该函数的文档: https : //developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale= en-US &redirectslug=DOM%2Felement.addEventListener
编辑:
现在处理这个问题的库更好了,你可以使用像 Fastclick 这样的替代品( https://github.com/ftlabs/fastclick )。
如果您必须支持同时支持鼠标和触摸的设备,另一种解决方案是使用捕获事件侦听器来停止发生的所有鼠标事件
触摸事件的信息(时间、位置或目标元素)可以记录在另一个捕获事件监听器中。
将鼠标专用代码包装在 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 部分。
此解决方案允许您侦听PointerEvents
如果它们存在),然后是TouchEvents
如果它们存在),然后是MouseEvents
如果其他两个都不存在)。 Mobile 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');
});
}
为移动 Web 应用程序创建快速按钮可以解决这个问题。
还要注意,当使用 IE10 时, preventDefault() 不会在 MSPointerDown 事件之后停止幽灵/合成/模拟鼠标事件,因此真正的跨浏览器解决方案更难。
当设备支持触摸事件时,您可以尝试在“单击”、“鼠标按下”或“鼠标向上”事件上退出该功能。
use.addEventListener("click",function(e){
// EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
if ("ontouchstart" in document.documentElement) return false;
// YOURMOUSEONLY CODE HERE
});
将事件侦听器添加到 touchstart 以将属性 data-touched 添加到元素。 添加另一个事件侦听器以单击检查数据接触。 如果它在那里,请防止默认并将其删除。 这是我的实现中的一些 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();
}
});
pointer...
事件具有mouse...
事件所缺少的pointerType
类型属性。 您可以使用此属性来检测和忽略由触摸而不是鼠标生成的事件。
前:
window.addEventListner('mousemove', (e) => {
/* No way to tell if this event came from a mouse or a finger */
console.log(':(');
});
后:
window.addEventListner('pointermove', (e) => {
if (e.pointerType !== 'mouse') return;
/* This event definitely came from a mouse */
console.log(':)');
});
您只需将mouse...
事件侦听器替换为pointer...
侦听器即可利用此属性。 pointer...
事件在现代浏览器中得到很好的支持(至少可以追溯到三年前)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.