[英]Make touch and wheel event listeners added by libraries as "passive"
我有两个项目:
jQuery
的Bootstrap
程序Vanilla JS
materialize-css
在对两个项目进行 Lighthouse 审计时,我曾经在一个项目上收到由materialize-css
引起的警告,在另一个项目上jQuery
引起的警告:
我说“曾经得到”,因为我确实设法为jQuery
修复它,只需应用以下解决方法:
const opts = (ns) => ... // some code deciding if browser supports passive
$.event.special.touchmove = { setup: function(_, ns, handle) { this.addEventListener('touchmove', handle, opts(ns)) } }
$.event.special.touchstart = { setup: function(_, ns, handle) { this.addEventListener('touchstart', handle, opts(ns)) } }
$.event.special.touchend = { setup: function(_, ns, handle) { this.addEventListener('touchend', handle, opts(ns)) } }
这似乎解决了jQuery
的问题,我不再收到这样的警告,一切似乎都正常。
现在,对于materialize-css
,我发现了这个 package默认被动事件(来自文档):
每次你声明一个新的事件监听器时,它基本上会自动设置 {passive: true }。
不幸的是,由于使用了e.preventDefault()
,该库确实使物化组件因触摸事件而中断...
有没有办法,类似于上面的jQuery
解决方法,来修复所有添加的materialize-css
事件侦听器? PS它不使用jQuery
首先,这只是一个警告,而不是错误。
有没有办法,类似于上面的 jQuery 解决方法,来修复所有添加的 materialize-css 事件侦听器? PS它不使用jQuery
是的,实际上有三种方式:
只需将{ passive: false }
作为第三个参数添加到所有没有 object 作为第三个参数的侦听器。 这将告诉浏览器.preventDefault()
可能会在这些事件上被调用。 但是,特别是在scroll
、 touchmove
和touchstart
事件上,当浏览器知道不会阻止事件的默认行为时,性能提升是相当可观的。 当标记为被动时,滚动将更加流畅,感知性能将显着提高。
我认为这个修复是徒劳的。 从性能 POV 中,您得到的正是您现在所拥有的,但控制台中不会出现任何警告。 恕我直言,更好的解决方案是保留警告。
将{ passive: true }
作为第三个参数添加到所有没有 object 作为第三个参数的侦听器。 这将告诉浏览器.preventDefault()
永远不会在这些事件上被调用。 您会看到性能提升,但任何依赖于阻止这些事件的代码都会中断。
注意:这是 jQuery 修复和default-passive-events
package 所做的,顺便说一句。
正确的方法是将 go 放入您正在修复的任何库的源代码中,找出可能会阻止哪些事件并为这些事件添加{ passive: false }
,同时为其他所有内容添加{ passive: true }
。
我认为找到所有在库中阻止事件的地方并不是一项艰巨的任务。
您可以在 fork 中执行此操作,理想情况下将其 PR-ing 回 lib 的 repo,让其他人受益,就像您从 lib 本身中受益一样。
这是解决方案1。
function patchEventListeners() {
const originalFn = EventTarget.prototype.addEventListener;
let supportsPassive = false;
document
.createElement("div")
.addEventListener("test", _ => {}, { get passive() { supportsPassive = true } });
if (supportsPassive) {
EventTarget.prototype.addEventListener = function(...args) {
if (
['scroll', 'touchmove', 'touchstart'].includes(args[0]) &&
(!args[2] || args[2].passive === undefined)
) {
args[2] = { ...(args[2] || {}), passive: false };
}
originalFn.call(this, ...args);
}
}
}
patchEventListeners();
上面的代码只“修补”了scroll
、 touchmove
和touchstart
事件(通过声明它们是非被动的)。 这使得警告 go 消失,而无需触及第三方代码。
注意:为了使其工作,function 必须在加载任何引发警告的库之前运行。 上面的代码只修补运行后添加的事件,它不会修补已经绑定的侦听器。
注意:对于解决方案 2,您显然需要将passive
覆盖更改为true
。
我创建了一个 npm package 遵循@tao 的“正确方法” ,不仅消除了警告,而且实际上提高了性能。 请参阅被动事件支持
它确实消除了MaterializeCSS和jQuery对我造成的警告。 如果您想使用它,请务必阅读自定义部分以仅将修复应用于您需要的事件:
import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport(['touchstart', 'touchmove'])
如果您不使用模块,请阅读文档以了解将其导入项目的其他方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.