为什么给 scroll 事件加 passive: true 后 preventDefault 不生效了?

百里春景 阅读 29

我在做一个自定义下拉刷新功能,需要监听 scroll 事件并阻止默认滚动,但加上 passive: truepreventDefault() 就报错了,说不能在 passive 事件里调用。可不加又会有性能警告,这咋办?

这是我的监听代码:

window.addEventListener('scroll', function(e) {
  if (scrollTop < 0) {
    e.preventDefault(); // 这里报错:Unable to preventDefault inside passive event listener
    // 自定义下拉逻辑...
  }
}, { passive: true });
我来解答 赞 19 收藏
二维码
手机扫码查看
2 条解答
UX-晴文
UX-晴文 Lv1
这个问题其实跟 WordPress 关系不大,但你都问到了,我就说说。

passive: true 就是这么设计的——浏览器用它来优化滚动性能,代价就是你不能调用 preventDefault。这是个不可调和的矛盾。

要实现下拉刷新,最好的办法是用 touch 事件而不是 scroll 事件:

let startY = 0;
document.addEventListener('touchstart', function(e) {
startY = e.touches[0].clientY;
}, { passive: false });

document.addEventListener('touchmove', function(e) {
const currentY = e.touches[0].clientY;
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

// 手指往下滑 + 在页面顶部 = 下拉刷新区域
if (currentY > startY && scrollTop <= 0) {
e.preventDefault(); // 这里不会报错
// 自定义下拉逻辑...
}
}, { passive: false });


{ passive: false } 改成 { passive: true } 性能警告就没了,但同时你也失去了阻止默认行为的能力。所以想要功能就顾不上那个警告,或者用现代浏览器的 CSS 属性 overscroll-behavior: contain 也能解决部分场景。

这就是前端开发的日常,浏览器设计就是这样鱼与熊掌不可兼得。
点赞 1
2026-03-10 22:11
IT人英杰
这问题我也踩过坑。passive: true 就是告诉浏览器你不会调用 preventDefault,所以它就能优化滚动性能。但你要阻止默认滚动,这俩需求冲突了。

解决方案是用两个监听器,一个 passive 的用来检测位置,另一个非 passive 的来阻止默认行为。直接上代码:

let shouldPrevent = false;

// passive监听器只检测不阻止
window.addEventListener('scroll', function() {
shouldPrevent = window.scrollTop < 0;
}, { passive: true });

// 非passive监听器实际阻止
window.addEventListener('scroll', function(e) {
if (shouldPrevent) {
e.preventDefault();
// 你的下拉刷新逻辑
}
});


其实这种下拉刷新最好用 touch 事件做,滚动事件坑太多了。不过你要非用 scroll 的话,上面这招能解决问题。
点赞 2
2026-03-05 23:19