Passive Event Listeners

介绍一个能提高页面人机交互效率的切实的方法 ———— Passive Event Listener(被动事件监听器)
这是一项已经被广泛支持的标准用法,一起来了解一下:

定义

EventTarget.addEventListener() 是为任何支持事件的对象提供监听器的方法。
基于现阶段的语法标准,其参数有几类:
target.addEventListener(type, listener, options);
target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); // wantsUntrusted 仅 Gecko/Mozilla 支持

当第三个参数 options 是对象且包含以下配置的时候,可以启用被动监听器这一特性。

target.addEventListener(type, listener ,{capture: Boolean, passive: Boolean, once: Boolean});
// capture:  Boolean,表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。
// once:  Boolean,表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除。
// passive: Boolean,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。

使用addEventListener注册事件监听时,只需要设定 options 对象中的 passive 属性为 true,即可实现事件被动监听。

作用与机理

在页面滚动(scrolling)过程中,追求的就是如丝般顺滑,但是通常scrolling动作会被touchstart、touchmove等事件(也可能是mouseup之类)干扰,比如页面内注册的touchmove包含了一些高密度运算制造了延时从而影响了滚动性能,甚至使用了event.preventDefault()方法完全阻止了页面滚动。

兼容性

根据 Can I Use – Passive Event Listener 的记录,被动事件监听已被较多浏览器所支持,不过追溯到Android的 4.x版本,基本不支持。
所以在使用的时候需要进行兼容。

友好检测

在实际应用中,通过以下代码来检测该功能是否被支持,如果支持则可以使用一个对象。下面附上检测代码:

var passiveSupported = false;

try {
  var options = Object.defineProperty({}, "passive", {
    get: function() {
      passiveSupported = true;
    }
  });

  window.addEventListener("test", null, options);
} catch(err) {}

检测代码用到了Object.defineProperty() 方法,该方法为目标对象动态添加属性,以上代码中Object.defineProperty()的第三个参数使用了数据描述符的方法。具体功能就是当执行window.addEventListener(“test”, null, options) 方法注册监听器时,会使用到options参数,此时如果支持 passive 属性,解析器就会访问 options.passive属性,而passive被定义了get描述方法,则被访问(取值)时,执行了 passiveSupported = true 这句。自然全局变量 passiveSupported 可以为后面的语句提供设置参考。

接下来,就利用passiveSupported参与配置:

eventTarget.addEventListener("mouseup", handleMouseUp, passiveSupported ? { passive: true } : false);

即当 passiveSupported = true 的时候设置passive属性为true,否则设置 useCapture 参数。

小案例

var elem = document.getElementById(‘elem’);
elem.addEventListener(‘touchmove’, function listener() { /* do something */ }, { passive: true });
添加passive参数后,touchmove事件不会阻塞页面的滚动(同样适用于鼠标的滚轮事件)

发表评论

电子邮件地址不会被公开。 必填项已用*标注