阻止浏览器touchmove默认行为

2019-07-01

最近移动端浏览器面板滑动问题(如下图):本来手指在面板上滑动的时候应该是面板上的内容跟着滑动,但是实际上是整个页面跟着滑动了,导致了面板上的内容跟着变了,从图上可以看出按钮都不见了;很显然这是由于touchmove时间的默认行为导致的。
虽然知道知道原因,刚开始是调用下面的方法:

1
document.addEventListener('touchmove', hendler,false);

发现怎么都不行,后来在一篇文章搜到了下面的代码,发现居然行:

1
document.addEventListener('touchmove', hendler, {passive : false});

可以看出,唯一的区别是第三个参数由false改成了对象{passive : false}

原来是由于浏览器无法预先知道一个事件处理函数中会不会调用preventDefault(),它需要等到事件处理函数执行完后,才能去执行默认行为,然而事件处理函数执行是要耗时的,这样一来就会导致页面卡顿。

Google为了解决这个问题,修订了addEventListener的第三个参数:开发者可以通过一个passive参数来告诉浏览器,当前页面内注册的事件监听器内部是否会调用preventDefault函数来阻止事件的默认行为,以便浏览器根据这个信息更好地做出决策来优化页面性能。

目前修订的规范中 options 对象可用的属性有三个:

1
2
3
4
5
addEventListener(type, listener, {
capture: false,//等价于之前的第三个参数
passive: false,//预先告知浏览器是否组织默认行为
once: false//once 属性就是表明该监听器是一次性的
})

Chrome 51 和 Firefox49已经支持passive属性。如果浏览器不支持,已经有牛人做了非常巧妙地 polyfill:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
}
});
window.addEventListener("test", null, opts);
} catch (e) {}
// Use our detect's results.
// passive applied if supported, capture will be false either way.
elem.addEventListener(
'touchstart',
fn,
supportsPassive ? { passive: true } : false
);

最后,如何取消addEventListener("foo", listener, {passive: true}) 添加的监听器该如何删除呢?答案是 removeEventListener("foo", listener) 就可以了,passive 可以省略,原因是:在浏览器内部,用来存储监听器的 map 的 key 是由事件类型,监听器函数,是否捕获这三者组成的,passiveonce 不在其中,理由显而易见,一个监听器同时是passive和非passive(以及同时是once和非once)是说不通的,如果你添加了两者,那么后添加的不算,浏览器会认为添加过了。

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章