为什么 touchmove不能随意使用 passive: true?
被动事件监听器的设计目的
浏览器开发团队引入被动事件监听器主要是为了解决滚动性能问题:
// 传统的事件监听器可能会阻止滚动
element.addEventListener('touchmove', function(e) {
// 如果这里有可能调用 e.preventDefault()
// 浏览器必须等待这个函数执行完才能知道是否要滚动
});
默认passive是false
核心矛盾点
当同时满足以下两个条件时会产生冲突:
-
事件监听器 可能 调用
preventDefault()阻止默认行为 -
但浏览器 需要立即知道 是否要执行默认行为(如滚动)
3. 被动事件监听器的解决方案
通过 { passive: true }明确告诉浏览器:
"这个监听器 绝对不会 调用 preventDefault(),你可以放心地立即执行默认行为"
element.addEventListener('touchmove', function(e) {
// 这里绝对不能调用 e.preventDefault()
// 浏览器可以立即执行滚动,不需要等待
}, { passive: true });
tableWrapper.addEventListener('touchmove', function(e) {
if (!isScrolling) {
// 这里根据条件可能会调用 e.preventDefault()
// 所以不能使用 passive: true
}
}, { passive: false }); // 必须设置为 false
如果错误地使用 passive: true会怎样?
// 错误示例!
tableWrapper.addEventListener('touchmove', function(e) {
if (shouldPreventScroll) {
e.preventDefault(); // 这行代码会被忽略,控制台会看到警告
}
}, { passive: true }); // 但这里声明了不会阻止默认行为
结果:
-
浏览器会忽略
preventDefault()调用 -
控制台会出现警告:
Unable to preventDefault inside passive event listener -
您的滚动控制逻辑会失效
需要阻止默认行为时
// 明确声明这不是被动监听器
element.addEventListener('touchmove', handler, { passive: false });
function handler(e) {
if (needToPrevent) {
e.preventDefault(); // 现在可以正常工作
}
}
不需要阻止默认行为时
// 声明为被动监听器以获得最佳性能
element.addEventListener('touchmove', handler, { passive: true });
function handler(e) {
// 这里绝对不能调用 e.preventDefault()
// 只是读取数据或执行不相关的逻辑
}
-
touchstart/touchend使用passive: true(因为这些事件通常不需要阻止默认行为) -
touchmove使用passive: false(因为确实需要条件性地阻止滚动)



1553

被折叠的 条评论
为什么被折叠?



