将库添加的触摸和滚轮事件侦听器设为 "passive"
Make touch and wheel event listeners added by libraries as "passive"
我有两个项目:
Bootstrap
与 jQuery
materialize-css
与 Vanilla JS
当 运行 对两个项目进行 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
,我发现这个包 default-passive-events(来自文档):
It basically will set { passive: true } automatically every time you
declare a new event listener.
不幸的是,由于使用 e.preventDefault()
...
,此库确实使实体化组件因触摸事件而中断
是否有类似于上述 jQuery
解决方法的方法来修复所有 materialize-css
添加的事件侦听器? P.S。它不使用 jQuery
首先,这只是一个警告,不是错误。
Is there a way, similar to jQuery workaround above, to fix all the materialize-css added event listeners? P.S. It does not use jQuery
是的,实际上有三种方式:
- 在不提高性能的情况下阅读警告
只需将 { passive: false }
作为第三个参数添加到所有没有对象作为第三个参数的侦听器。这将告诉浏览器可能会在这些事件上调用 .preventDefault()
。但是,尤其是在 scroll
、touchmove
和 touchstart
事件上,当浏览器知道默认行为不会在事件上被阻止时,性能提升是相当可观的。当标记为被动时,滚动会更平滑,感知性能会显着提高。
- 通过可能破坏功能来提高性能
将 { passive: true }
作为第三个参数添加到所有没有对象作为第三个参数的侦听器。这将告诉浏览器永远不会在这些事件上调用 .preventDefault()
。您会看到性能提升,但依赖于防止这些事件的代码将会中断。
注意:这就是 jQuery 修复和 default-passive-events
包所做的,顺便说一句。
- 正确的方法
正确的方法是进入你正在修复的任何库的源代码,弄清楚哪些事件可能会被阻止并为那些添加 { passive: false }
,同时为所有内容添加 { passive: true }
否则。
我认为在库中找到所有阻止事件发生的地方并不是一项艰巨的任务。
您可以在 fork 中执行此操作,最好将其 PR 返回到 lib 的存储库中,以便其他人受益,就像您从 lib 本身中受益一样。
这是解决方案 1。
function patchScrollBlockingListeners() {
let supportsPassive = false;
const x = document.createElement("x");
x.addEventListener("cut", () => 1, {
get passive() { supportsPassive = true; return !!1 }
});
x.remove();
if (supportsPassive) {
const originalFn = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(...args) {
if (
['scroll', 'touchmove', 'touchstart'].includes(args[0]) &&
(typeof args[2] !== 'object' || args[2].passive === undefined)
) {
args[2] = {
...(typeof args[2] === 'object' ? args[2] : {}),
passive: false
};
}
originalFn.call(this, ...args);
}
}
}
patchScrollBlockingListeners();
以上代码仅“修补”scroll
、touchmove
和 touchstart
事件(通过声明它们是非被动的)。这会使警告消失,而无需触及第三方代码。
注意:为了使其工作,函数必须是 运行 在加载任何库抛出警告之前。上面的代码只修补了 运行 之后添加的事件,它没有修补已经绑定的侦听器。
注意:解决方案 2 是相同的代码,只是 passive
覆盖设置为 true
。
另一个相当重要的注意事项: 虽然我不能保证它对每个人都有效,但将以下内容传递给 passive
对我有用“修补”很多项目中的很多库:
passive: typeof args[2] === "boolean" ? args[2] : true
它遵循以前的 addEventListener
语法(其中第 3 个参数是 passive
本身,如 boolean
)并在根本未指定时将其设置为 true
.然而,这将中断未指定 passive
的事件,并且在某些情况下事件被取消,这就是为什么我没有在上面包含它。
我创建了一个遵循@tao 的“正确方法” 的 npm 包,不仅消除了警告,而且实际上提高了性能。参见 passive-events-support
它确实为我删除了由 MaterializeCSS 和 jQuery 引起的警告。如果您想使用它,请务必阅读自定义部分以仅对您需要的事件应用修复:
import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport(['touchstart', 'touchmove'])
如果您不使用模块,请阅读文档了解将其导入项目的其他方法。
我有两个项目:
Bootstrap
与jQuery
materialize-css
与Vanilla JS
当 运行 对两个项目进行 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
,我发现这个包 default-passive-events(来自文档):
It basically will set { passive: true } automatically every time you declare a new event listener.
不幸的是,由于使用 e.preventDefault()
...
是否有类似于上述 jQuery
解决方法的方法来修复所有 materialize-css
添加的事件侦听器? P.S。它不使用 jQuery
首先,这只是一个警告,不是错误。
Is there a way, similar to jQuery workaround above, to fix all the materialize-css added event listeners? P.S. It does not use jQuery
是的,实际上有三种方式:
- 在不提高性能的情况下阅读警告
只需将 { passive: false }
作为第三个参数添加到所有没有对象作为第三个参数的侦听器。这将告诉浏览器可能会在这些事件上调用 .preventDefault()
。但是,尤其是在 scroll
、touchmove
和 touchstart
事件上,当浏览器知道默认行为不会在事件上被阻止时,性能提升是相当可观的。当标记为被动时,滚动会更平滑,感知性能会显着提高。
- 通过可能破坏功能来提高性能
将 { passive: true }
作为第三个参数添加到所有没有对象作为第三个参数的侦听器。这将告诉浏览器永远不会在这些事件上调用 .preventDefault()
。您会看到性能提升,但依赖于防止这些事件的代码将会中断。
注意:这就是 jQuery 修复和 default-passive-events
包所做的,顺便说一句。
- 正确的方法
正确的方法是进入你正在修复的任何库的源代码,弄清楚哪些事件可能会被阻止并为那些添加 { passive: false }
,同时为所有内容添加 { passive: true }
否则。
我认为在库中找到所有阻止事件发生的地方并不是一项艰巨的任务。
您可以在 fork 中执行此操作,最好将其 PR 返回到 lib 的存储库中,以便其他人受益,就像您从 lib 本身中受益一样。
这是解决方案 1。
function patchScrollBlockingListeners() {
let supportsPassive = false;
const x = document.createElement("x");
x.addEventListener("cut", () => 1, {
get passive() { supportsPassive = true; return !!1 }
});
x.remove();
if (supportsPassive) {
const originalFn = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(...args) {
if (
['scroll', 'touchmove', 'touchstart'].includes(args[0]) &&
(typeof args[2] !== 'object' || args[2].passive === undefined)
) {
args[2] = {
...(typeof args[2] === 'object' ? args[2] : {}),
passive: false
};
}
originalFn.call(this, ...args);
}
}
}
patchScrollBlockingListeners();
以上代码仅“修补”scroll
、touchmove
和 touchstart
事件(通过声明它们是非被动的)。这会使警告消失,而无需触及第三方代码。
注意:为了使其工作,函数必须是 运行 在加载任何库抛出警告之前。上面的代码只修补了 运行 之后添加的事件,它没有修补已经绑定的侦听器。
注意:解决方案 2 是相同的代码,只是 passive
覆盖设置为 true
。
另一个相当重要的注意事项: 虽然我不能保证它对每个人都有效,但将以下内容传递给 passive
对我有用“修补”很多项目中的很多库:
passive: typeof args[2] === "boolean" ? args[2] : true
它遵循以前的 addEventListener
语法(其中第 3 个参数是 passive
本身,如 boolean
)并在根本未指定时将其设置为 true
.然而,这将中断未指定 passive
的事件,并且在某些情况下事件被取消,这就是为什么我没有在上面包含它。
我创建了一个遵循@tao 的“正确方法” 的 npm 包,不仅消除了警告,而且实际上提高了性能。参见 passive-events-support
它确实为我删除了由 MaterializeCSS 和 jQuery 引起的警告。如果您想使用它,请务必阅读自定义部分以仅对您需要的事件应用修复:
import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport(['touchstart', 'touchmove'])
如果您不使用模块,请阅读文档了解将其导入项目的其他方法。