繁体   English   中英

将库添加的触摸和滚轮事件侦听器设置为“被动”

[英]Make touch and wheel event listeners added by libraries as "passive"

我有两个项目:

  1. jQueryBootstrap程序
  2. 使用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

是的,实际上有三种方式:

  1. 在不提高性能的情况下阅读警告

只需将{ passive: false }作为第三个参数添加到所有没有 object 作为第三个参数的侦听器。 这将告诉浏览器.preventDefault()可能会在这些事件上被调用。 但是,特别是在scrolltouchmovetouchstart事件上,当浏览器知道不会阻止事件的默认行为时,性能提升是相当可观的。 当标记为被动时,滚动将更加流畅,感知性能将显着提高。
我认为这个修复是徒劳的。 从性能 POV 中,您得到的正是您现在所拥有的,但控制台中不会出现任何警告。 恕我直言,更好的解决方案是保留警告。

  1. 通过可能破坏功能来提高性能

{ passive: true }作为第三个参数添加到所有没有 object 作为第三个参数的侦听器。 这将告诉浏览器.preventDefault()永远不会在这些事件上被调用。 您会看到性能提升,但任何依赖于阻止这些事件的代码都会中断。

注意:这是 jQuery 修复和default-passive-events package 所做的,顺便说一句。

  1. 正确的方法

正确的方法是将 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();
    

上面的代码只“修补”了scrolltouchmovetouchstart事件(通过声明它们是非被动的)。 这使得警告 go 消失,而无需触及第三方代码。
注意:为了使其工作,function 必须在加载任何引发警告的库之前运行。 上面的代码只修补运行后添加的事件,它不会修补已经绑定的侦听器。

注意:对于解决方案 2,您显然需要将passive覆盖更改为true

我创建了一个 npm package 遵循@tao 的“正确方法” ,不仅消除了警告,而且实际上提高了性能。 请参阅被动事件支持

它确实消除了MaterializeCSSjQuery对我造成的警告。 如果您想使用它,请务必阅读自定义部分以仅将修复应用于您需要的事件:

import { passiveSupport } from 'passive-events-support/src/utils'

passiveSupport(['touchstart', 'touchmove'])

如果您不使用模块,请阅读文档以了解将其导入项目的其他方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM