最近做项目经常在 chrome 的控制台看到如下提示:
Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
于是 Google 了一番,找到这篇文章,有了详细解释。Making touch scrolling fast by default
简而言之:
preventDefault()
,这就导致了浏览器不能及时响应滚动,略有延迟。chrome56
开始,在 window、document
和 body
上注册的touchstart
和 touchmove
事件处理函数,会默认为是 passive: true
。浏览器忽略 preventDefault()
就可以第一时间滚动了。举例:
wnidow.addEventListener('touchmove', func) 效果和下面一句一样
wnidow.addEventListener('touchmove', func, {
passive: true })
这就导致了一个问题:
如果在以上这 3 个元素的 touchstart
和 touchmove
事件处理函数中调用 e.preventDefault()
,会被浏览器忽略掉,并不会阻止默认行为。
测试:
body {
margin: 0;
height: 2000px;
background: linear-gradient(to bottom, red, green);
}
// 在 chrome56 中,照样滚动,而且控制台会有提示,blablabla
window.addEventListener('touchmove', e => e.preventDefault())
那么如何解决这个问题呢?不让控制台提示,而且 preventDefault()
有效果呢?
两个方案:
1、注册处理函数时,用如下方式,明确声明为不是被动的
window.addEventListener('touchmove', func, {
passive: false })
2、应用 CSS 属性 touch-action: none;
这样任何触摸事件都不会产生默认行为,但是 touch
事件照样触发。
touch-action
还有很多选项,详细请参考touch-action
[注]未来可能所有的元素的 touchstart touchmove
事件处理函数都会默认为 passive: true
相信如果用谷歌浏览器做移动端页面的时候
用touch
事件的时候应该遇到过这个东东吧
documet.addEventListener("touchstart",function(){
console.log(123);
});
[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive.
翻译过来就是
违反:没有添加被动事件监听器来阻止’
touchstart
‘事件,请考虑添加事件管理者’passive
’,以使页面更加流畅。
出现如上提示这可能是由于console
的过滤器选择了Verbose
于是你检查了代码 发现并没有问题 那么这到底是啥呢
强迫症的我 上网百度了 一下
于是就有所了解
以前的监听器都是这样的
element.addEventListener("touchstart",fn,true|false);
true
是事件捕获阶段执行
false
是事件冒泡阶段执行
这里不细说
没有第三个参数的时候默认为false
第三个参数还可以是对象
element.addEventListener("touchstart",fn,
{
capture: Boolean, passive: Boolean, once: Boolean}
});
第一个参数的意思 true|false
事件捕获阶段冒泡阶段
第二个参数 true|flase
不能调用 | 可以调用preventDefault()
第三个参数 once true|false
只能执行一次fn
| 不限制
那问题来了 为什么要使用对象 并且要用passive
呢 是因为事件里面的fn
执行时需要时间滴
你想呀 执行代码的时候 比如 mousewheel
的时候 鼠标滚轮让滚动条动 可是你调用
preventDefault()
取消了事件的默认行为 那你说 它到底该动还是不动,浏览器一脸懵逼
它只有在fn
里面的代码执行完之后才会知道到底要不要取消默认行为 这样等待的时间不就
白白浪费掉了吗 是性能低下 在执行fn
之前就告诉 它 是否取消默认行为
这不就你知我长短 我知你深浅了吗
由于这个只有谷歌有 所以兼容处理 不认识的大神写的
try{
var passiveSupported=false;
var opts=Object.defineProperty({
},"passive",{
get:function(){
passiveSupported=true;
}
});
document.addEventListener("自己决定",null,opts);
}
catch(e){
}
document.addEventListener("touchstart",fn,passiveSupported?{
"passive":true}:false);
这么看不得劲
挨张图片
有的人可能不知道 Object.defineProperty()
我就说在这需要用知道的
就是当访问{}
的 passive
属性的时候 执行get
方法
{}
不就是new Object()
的语法糖吗
console.log(options)
就是;
所以你明白了吧
当触发这个的时候 就是访问options
的passive
属性 然后passiveSupported=true
“test
” 你随意设置
1.滑动时候警告[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive.
2.解决方案
解决办法1:
在touch
的事件监听方法上绑定第三个参数{ passive: false }
,
通过传递 passive
为 false
来明确告诉浏览器:事件处理程序调用 preventDefault
来阻止默认滑动行为。
elem.addEventListener(
'touchstart',
fn,
{
passive: false }
);
解决办法2:
* {
touch-action: pan-y; }
// 使用全局样式样式去掉