Lighthouse 报“Best Practices”里有被动事件监听器问题,怎么解决?

W″保艳 阅读 22

我在用 Lighthouse 做性能审计时,发现 Best Practices 里提示“Uses passive event listeners to improve scrolling performance”,但我不太确定哪里触发了这个问题。我页面里确实有个 touchstart 事件用来处理滑动,但加了 passive: true 后反而报错说 preventDefault 被忽略了。

这是我的代码:

document.addEventListener('touchstart', function(e) {
  if (someCondition) {
    e.preventDefault();
  }
}, { passive: true });

现在有点懵,到底该不该用 passive?如果用了 preventDefault 就失效,不用又会被 Lighthouse 扣分,咋办?

我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
シ世昌
シ世昌 Lv1
这问题其实挺常见的,passive 和 preventDefault 天然冲突,不能兼得。

先说原理,passive: true 是告诉浏览器"我保证不会调用 preventDefault",这样浏览器就不用等 JS 跑完,可以直接开始滚动,性能上会好很多。但你代码里又调了 preventDefault,相当于承诺了不阻止却又阻止,浏览器当然懵了。

解决办法是用 CSS 的 touch-action 属性来替代 JS 里的 preventDefault。这才是正解,性能上也更优,毕竟 CSS 的处理在合成线程,比主线程的 JS 快得多。

假设你的 someCondition 是想阻止水平滑动但保留垂直滚动,直接在元素上设置:

.your-element {
touch-action: pan-y;
}


这样浏览器就知道这个元素只能垂直滚动,水平方向的触摸行为会被自动忽略,根本不需要 JS 插手。然后你的 JS 事件监听器就可以放心设置 passive: true 了,甚至如果只是用来检测手势,可以把 preventDefault 那块逻辑删掉。

如果你的场景是某些条件下完全禁止所有触摸行为,可以用 touch-action: none,但这个要谨慎,会把所有滚动都干掉。

改完之后的代码大概这样:

document.addEventListener('touchstart', function(e) {
if (someCondition) {
// 处理你的逻辑,但不要 preventDefault
// 阻止行为的事情交给 CSS touch-action
}
}, { passive: true });


还有一种情况,如果你确实必须在 JS 里动态判断是否阻止默认行为(比如条件很复杂,CSS 搞不定),那就老老实实设置 passive: false,Lighthouse 扣分就扣吧,功能正确比分数重要。不过说实话,大部分场景 touch-action 都能覆盖,真正需要动态 preventDefault 的情况其实很少见。
点赞 2
2026-03-01 22:10
Code°玉银
这问题其实挺经典的,passive 和 preventDefault 本质上就是互斥的,你现在的写法确实有矛盾。

先说结论:如果你必须在 touchstart 里调用 preventDefault,那就得显式设置 passive: false,Lighthouse 的警告可以忽略,或者用 CSS touch-action 来解决。

浏览器默认会把 touchstart/touchmove 这类触摸事件设为 passive: true,为了滚动性能。你主动加 passive: true 又在里面调 preventDefault,浏览器就直接无视你的阻止行为了。

两种解决方案。

第一种,如果你确实需要阻止默认行为,就老老实实写 passive: false:

document.addEventListener('touchstart', function(e) {
if (someCondition) {
e.preventDefault();
}
}, { passive: false });


这样写 Lighthouse 还是会报警告,但功能是对的。这种情况下警告可以忽略,因为你确实需要阻止默认行为,这是合理的 trade-off。

第二种,更优雅的方式是用 CSS 的 touch-action 属性来替代 JS 里的 preventDefault。比如你只是想阻止某个元素的默认滚动或缩放行为:

.your-element {
touch-action: none; /* 禁止所有默认触摸行为 */
/* 或者 */
touch-action: pan-y; /* 只允许垂直滚动 */
touch-action: manipulation; /* 允许滚动和缩放,禁止双击缩放 */
}


这样更清晰,CSS 层面就限制了触摸行为,JS 里就不用调 preventDefault 了,事件监听器可以安心用 passive: true,Lighthouse 也不会报警告。

如果你的 someCondition 逻辑比较复杂,必须在 JS 里动态判断,那就用第一种方案,Lighthouse 的警告不用太纠结,它只是个静态检查工具,不理解你的业务逻辑。
点赞 1
2026-02-28 23:28