touchmove事件 与 被动事件(passive event) 问题

touchmove 事件 与 被动事件(passive event) 问题

[TOC]

产生原因:

  1. 条件 1:使用监听事件时候,第三个参数配置了 passive 为 true(说明指定了这个监听为一个被动监听)
1
window.addEventListener("touchmove", handler, { passive: true });
  1. 条件 2:上条件中的被动监听的 handler 中调用了
1
2
3
4
5
function handler() {
//阻止默认事件,如点击<a>标签阻止其默认跳转事件
event.preventDefault();
//其他逻辑...
}

上述两个条件同时成立的时候,就会报标题中错误或警告。

本质:
谷歌浏览器对 event.preventDefault()(默认事件阻止)的检测机制变化导致的(听不懂?直接看下面)。

老版本:当用户触发我们定义的监听事件时候(如条件 1 中的“touchmove”事件),浏览器会主动检测对应的 handler 代码中是否有 event.preventDefault(),以便进行默认事件阻止。但是这样做会增加响应时间,用户体验受到影响;

新版本

默认不再检测 event.preventDefault(),直接响应用户操作。这相当于把我们定义的事件监听都设置成了被动事件监听。具体代码就是:

1
2
window.addEventListener("touchmove", handler);
window.addEventListener("touchmove", handler, { passive: true });

上面两个代码效果相同,我们经常用第一条,不知不觉中定义了一个被动监听事件。

那么问题就来了,我们不知道我们的事件已经默认被定义为了被动事件监听。结果我们在这个事件监听中调用了 event.preventDefault(),浏览器就不高兴了,导致报错,告诉你:

“你定义的事件不是一个被动事件监听吗?不就是告诉我为了提高响应速度不要处理 event.preventDefault()吗?为啥你还要调用 event.preventDefault()!”

看了我们已经找到问题所在了。

总结: 被动事件监听不能调用 event.preventDefault()。

值得说的是: Passive Event Listeners 特性当前仅支持 mousewheel/touch 相关事件。


解决办法:

1、声明事件监听的时候设置为主动事件监听:

1
window.addEventListener(‘touchmove’, handler, { passive: false});

2、设置监听事件绑定的 dom 的 CSS 为:

1
touch-action: none;

表示当触控事件发生在绑定的 dom 上时,不进行任何操作。

引申:

在解决下图出现的警告时,通常使用 default-passive-events 包。可以解决。

该问题主要是因为 chrome51 后 google 为了滚动等事件的性能,所有的事件都需要默认绑定 被动监听器了,但 element 中并没有绑定,所有会抛出警告。

_default-passive-events_ 包,可以通过修改事件的 passive 设置为 true, 解决这个警告。又因为element是在事件监听器的callback(handler)中使用`event.preventDefault()`清除默认事件的。所有就完全成全了上述的 `报错的产生原因`,导致上述的**报错**。所以在使用element组件时不建议再用 _default-passive-events_ 包。警告就警告吧。

ps:

关于 touch-action 还有很多设置,我也在学习中。

本文参考了https://blog.csdn.net/lijingshan34/article/details/88350456和https://juejin.im/post/5ad804c1f265da504547fe68。理解上不对之处欢迎指出。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!