EventTarget方法:addEventListener()

2019-01-19 10:02 更新

該EventTarget方法addEventListener()設(shè)置一個(gè)函數(shù),只要將指定的事件傳遞給目標(biāo),就會(huì)調(diào)用該函數(shù)。共同目標(biāo)是Element,, Document和Window,但目標(biāo)可以是支持事件的任何對(duì)象(例如XMLHttpRequest)。

addEventListener()通過(guò)向調(diào)用它的EventTarget上的指定事件類型的事件偵聽器列表添加實(shí)現(xiàn)EventListener的函數(shù)或?qū)ο髞?lái)工作。

語(yǔ)法

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
target.addEventListener(type, listener[, useCapture, wantsUntrusted  ]); // Gecko/Mozilla only

參數(shù)部分

type
一個(gè)區(qū)分大小寫的字符串,表示要偵聽的事件類型。
listener
當(dāng)發(fā)生指定類型的事件時(shí)接收通知(實(shí)現(xiàn)Event接口的對(duì)象)的對(duì)象。這必須是實(shí)現(xiàn)EventListener接口的對(duì)象,或JavaScript函數(shù)。
options (可選)
一個(gè)options對(duì)象,它指定有關(guān)事件偵聽器的特征??捎眠x項(xiàng)包括:
  • capture:Boolean,表示在將這種類型的事件將被調(diào)度到已注冊(cè)的listener,在被調(diào)度到DOM樹下面的任何EventTarget之前。
  • once:Boolean,表示listener應(yīng)該在添加后最多調(diào)用一次。如果為true,則會(huì)在調(diào)用時(shí)自動(dòng)刪除listener。
  • passive:Boolean,如果為true,則表示由listener指定的函數(shù)永遠(yuǎn)不會(huì)調(diào)用preventDefault()。如果被動(dòng)偵聽器進(jìn)行了調(diào)用preventDefault(),則除了生成控制臺(tái)警告之外,用戶代理將不執(zhí)行任何操作。
  •  mozSystemGroup:Boolean,表示應(yīng)將偵聽器添加到系統(tǒng)組。僅適用于在XBL中運(yùn)行的代碼或Firefox瀏覽器的chrome中。
useCapture (可選)
一個(gè)Boolean,指示是否在將這種類型的事件將被調(diào)度到已注冊(cè)的listener,在被調(diào)度到DOM樹下面的任何EventTarget之前。向上冒泡樹的事件不會(huì)觸發(fā)指定使用捕獲的偵聽器。當(dāng)兩個(gè)元素都已為該事件注冊(cè)了句柄時(shí),事件冒泡和捕獲是兩種傳播事件的方式,這些事件發(fā)生在嵌套在另一個(gè)元素中的元素中。事件傳播模式確定元素接收事件的順序。如果未指定,則useCapture默認(rèn)為false。
注意:對(duì)于附加到事件目標(biāo)的事件偵聽器,事件處于目標(biāo)階段,而不是捕獲和冒泡階段。無(wú)論useCapture參數(shù)如何,目標(biāo)階段中的事件將按照它們注冊(cè)的順序觸發(fā)元素上的所有偵聽器。
注意: useCapture并非總是可選的。理想情況下,您應(yīng)該將其包含在最廣泛的瀏覽器兼容性中。
wantsUntrusted 
Firefox(Gecko)特有的參數(shù)。如果為true,偵聽器接收由Web內(nèi)容調(diào)度的合成事件(在瀏覽器chrom中默認(rèn)為false,常規(guī)網(wǎng)頁(yè)中默認(rèn)是true)。此參數(shù)對(duì)于加載項(xiàng)中的代碼以及瀏覽器本身很有用。

返回值部分

undefined

使用說(shuō)明

事件監(jiān)聽器回調(diào)部分

事件偵聽器可以指定為回調(diào)函數(shù)或?qū)崿F(xiàn)EventListener的對(duì)象,其handleEvent()方法用作回調(diào)函數(shù)。

回調(diào)函數(shù)本身具有與handleEvent()方法具有相同的參數(shù)和返回值;也就是說(shuō),回調(diào)接受一個(gè)參數(shù):一個(gè)基于Event描述已發(fā)生事件的對(duì)象,它不返回任何內(nèi)容。

例如,可以使用一個(gè)事件處理程序回調(diào)同時(shí)處理fullscreenchange和fullscreenerror,可能是如下所示:

function eventHandler(event) {
  if (event.type == fullscreenchange) {
    /* handle a full screen toggle */
  } else /* fullscreenerror */ {
    /* handle a full screen toggle error */
  }
}

安全地檢測(cè)選項(xiàng)支持部分

在舊版本的DOM規(guī)范中,第三個(gè)參數(shù)addEventListener()是一個(gè)布爾值,指示是否使用捕獲。隨著時(shí)間的推移,很明顯需要更多的選擇。不是向函數(shù)添加更多參數(shù)(在處理可選值時(shí)使事情變得非常復(fù)雜),而是將第三個(gè)參數(shù)更改為一個(gè)對(duì)象,該對(duì)象可以包含定義選項(xiàng)值的各種屬性,以配置刪除事件偵聽器的過(guò)程。

因?yàn)榕f版瀏覽器(以及一些不太舊的瀏覽器)仍假設(shè)第三個(gè)參數(shù)是布爾值,所以您需要構(gòu)建代碼以智能地處理此場(chǎng)景。您可以通過(guò)對(duì)您感興趣的每個(gè)選項(xiàng)使用特征檢測(cè)來(lái)執(zhí)行此操作。

例如,如果要檢查passive選項(xiàng):

var passiveSupported = false;

try {
  var options = {
    get passive() { // This function will be called when the browser
                    //     attempts to access the passive property.
      passiveSupported = true;
    }
  };

  window.addEventListener("test", options, options);
  window.removeEventListener("test", options, options);
} catch(err) {
  passiveSupported = false;
}

這將創(chuàng)建一個(gè)具有該passive屬性的getter函數(shù)的options對(duì)象;getter設(shè)置一個(gè)標(biāo)志,passiveSupported,如果它被調(diào)用,則passiveSupported為true。這意味著如果瀏覽器檢查對(duì)象passive上options屬性的值,passiveSupported則將其設(shè)置為true;否則,它將保持為false。然后我們調(diào)用addEventListener()來(lái)設(shè)置假的事件處理程序,指定這些選項(xiàng),以便在瀏覽器將對(duì)象識(shí)別為第三個(gè)參數(shù)時(shí)檢查選項(xiàng)。然后,我們調(diào)用removeEventListener()給自己清理。(注意,handleEvent()在未調(diào)用的事件偵聽器上會(huì)被忽略。)

您可以通過(guò)這種方式檢查是否支持任何選項(xiàng)。只需使用類似于上面顯示的代碼為該選項(xiàng)添加一個(gè)getter。

然后,當(dāng)您想要?jiǎng)?chuàng)建使用相關(guān)選項(xiàng)的實(shí)際事件偵聽器時(shí),您可以執(zhí)行以下操作:

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

這里我們?yōu)閟omeElement元素上的mouseup事件添加一個(gè)監(jiān)聽器。對(duì)于第三個(gè)參數(shù),如果passiveSupported是true,我們指定一個(gè)passive設(shè)置為true的options對(duì)象;否則,我們知道我們需要傳遞一個(gè)布爾值,并且我們傳遞false作為useCapture參數(shù)的值。

如果您愿意,可以使用Modernizr或Detect It等第三方庫(kù)為您進(jìn)行此測(cè)試。

示例

添加一個(gè)簡(jiǎn)單的監(jiān)聽器

此示例演示如何使用addEventListener()監(jiān)視鼠標(biāo)對(duì)元素的單擊。

HTML

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>

JavaScript

// Function to change the content of t2
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

在此代碼中,modifyText()是使用addEventListener()注冊(cè)的click事件的偵聽器。單擊表格中的任何位置都會(huì)冒泡到處理程序,并運(yùn)行modifyText()。

事件監(jiān)聽anonymous函數(shù)

在這里,我們將看看如何使用anonymous函數(shù)將參數(shù)傳遞給事件監(jiān)聽器。

HTML

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>

JavaScript

// Function to change the content of t2
function modifyText(new_text) {
  var t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;    
}
 
// Function to add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", function(){modifyText("four")}, false);

請(qǐng)注意,偵聽器是一個(gè)匿名函數(shù),它封裝了代碼,然后代碼可以向modifyText()函數(shù)發(fā)送參數(shù),該函數(shù)負(fù)責(zé)實(shí)際響應(yīng)事件。

具有arrow功能的事件監(jiān)聽器

此示例演示了使用arrow函數(shù)表示法實(shí)現(xiàn)的簡(jiǎn)單事件偵聽器。

HTML

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>

JavaScript

// Function to change the content of t2
function modifyText(new_text) {
  var t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;    
}
 
// Add event listener to table with an arrow function
var el = document.getElementById("outside");
el.addEventListener("click", () => { modifyText("four"); }, false);

請(qǐng)注意,雖然anonymous和arrow函數(shù)相似,但它們具有不同的this綁定。雖然anonymous(和所有傳統(tǒng)的JavaScript函數(shù))創(chuàng)建自己的this綁定,但arrow函數(shù)繼承了包含函數(shù)的this綁定。

這意味著當(dāng)使用arrow函數(shù)時(shí),包含函數(shù)可用的變量和常量也可用于事件處理程序。

選項(xiàng)用法示例

HTML

<div class="outer">
    outer, once & none-once
    <div class="middle" target="_blank">
        middle, capture & none-capture
        <a class="inner1"  rel="external nofollow" target="_blank"  target="_blank">
            inner1, passive & preventDefault(which is not allowed)
        </a>
        <a class="inner2"  rel="external nofollow" target="_blank"  target="_blank">
            inner2, none-passive & preventDefault(not open new page)
        </a>
    </div>
</div>

CSS

    .outer, .middle, .inner1, .inner2 {
        display:block;
        width:520px;
        padding:15px;
        margin:15px;
        text-decoration:none;
    }
    .outer{
        border:1px solid red;
        color:red;
    }
    .middle{
        border:1px solid green;
        color:green;
        width:460px;
    }
    .inner1, .inner2{
        border:1px solid purple;
        color:purple;
        width:400px;
    }

JavaScript

    let outer  = document.getElementsByClassName('outer') [0];
    let middle = document.getElementsByClassName('middle')[0];
    let inner1 = document.getElementsByClassName('inner1')[0];
    let inner2 = document.getElementsByClassName('inner2')[0];

    let capture = {
        capture : true
    };
    let noneCapture = {
        capture : false
    };
    let once = {
        once : true
    };
    let noneOnce = {
        once : false
    };
    let passive = {
        passive : true
    };
    let nonePassive = {
        passive : false
    };
    
    
    outer .addEventListener('click', onceHandler, once);
    outer .addEventListener('click', noneOnceHandler, noneOnce);
    middle.addEventListener('click', captureHandler, capture);
    middle.addEventListener('click', noneCaptureHandler, noneCapture);
    inner1.addEventListener('click', passiveHandler, passive);
    inner2.addEventListener('click', nonePassiveHandler, nonePassive);

    function onceHandler(event)
    {
        alert('outer, once');
    }
    function noneOnceHandler(event)
    {
        alert('outer, none-once, default');
    }
    function captureHandler(event)
    {
        //event.stopImmediatePropagation();
        alert('middle, capture');
    }
    function noneCaptureHandler(event)
    {
        alert('middle, none-capture, default');
    }
    function passiveHandler(event)
    {
        // Unable to preventDefault inside passive event listener invocation.
        event.preventDefault();
        alert('inner1, passive, open new page');
    }
    function nonePassiveHandler(event)
    {
        event.preventDefault();
        //event.stopPropagation();
        alert('inner2, none-passive, default, not open new page');
    }

在options對(duì)象中使用特定值之前,最好確保用戶的瀏覽器支持它,因?yàn)檫@并非所有瀏覽器都支持的附加功能。

其他說(shuō)明

為何使用addEventListener?

addEventListener()是注冊(cè)W3C DOM中指定的事件偵聽器的方法。好處如下:

  • 它允許為事件添加多個(gè)處理程序。這對(duì)于AJAX庫(kù),JavaScript模塊或需要與其他庫(kù)/擴(kuò)展很好地協(xié)作的任何其他類型的代碼特別有用。
  • 當(dāng)監(jiān)聽器被激活時(shí)(捕獲與冒泡),它可以讓您對(duì)階段進(jìn)行更精細(xì)的控制。
  • 它適用于任何DOM元素,而不僅僅是HTML元素。

注冊(cè)事件偵聽器的另一種舊方法如下所述。

在事件發(fā)送部分添加偵聽器

如果在處理事件的過(guò)程中向EventTarget添加了一個(gè)EventListener,則該事件不會(huì)觸發(fā)偵聽器。但是,在事件流的后期階段(例如冒泡階段)可能會(huì)觸發(fā)相同的偵聽器。

多個(gè)相同的事件監(jiān)聽器

如果在有相同參數(shù)的相同EventTarget上注冊(cè)了多個(gè)相同的EventListener s ,則丟棄重復(fù)的實(shí)例。它們不會(huì)導(dǎo)致EventListener被調(diào)用兩次,并且不需要使用該removeEventListener()方法手動(dòng)刪除它們。但請(qǐng)注意,當(dāng)使用anonymous函數(shù)作為處理程序時(shí),這樣的偵聽器將不相同,因?yàn)閍nonymous函數(shù)是不相同的,即使使用簡(jiǎn)單地重復(fù)調(diào)用的SAME不變的源代碼定義,即使在循環(huán)中也是如此。然而,在這種情況下重復(fù)定義相同的命名函數(shù)可能更成問(wèn)題。

this處理程序部分中的值

通常需要引用觸發(fā)事件處理程序的元素,例如對(duì)一組類似元素使用泛型處理程序時(shí)。

如果使用addEventListener()將處理程序函數(shù)附加到元素,則處理程序內(nèi)部的this值是對(duì)元素的引用。它與傳遞給處理程序的event參數(shù)的currentTarget屬性值相同。

如果在HTML源代碼中的元素上指定了事件處理程序(例如,onclick),則屬性值中的JavaScript代碼將有效地包裝在處理函數(shù)中,該函數(shù)以與addEventListener() 一致的方式綁定this值。this代碼中出現(xiàn)的內(nèi)容表示對(duì)元素的引用。請(qǐng)注意,this函數(shù)內(nèi)部的值(由屬性值中的代碼調(diào)用)的行為與標(biāo)準(zhǔn)規(guī)則相同。這在以下示例中顯示:

<table id="t" onclick="modifyText();">
  . . .

帶有modifyText()的this的值是對(duì)全局對(duì)象Window的引用(或者在嚴(yán)格模式的情況下的undefined)。

使用bind()指定this

該Function.prototype.bind()方法允許您指定應(yīng)該用于對(duì)給定函數(shù)的所有調(diào)用的this值。這使您可以輕松繞過(guò)不清楚this將要發(fā)生什么的問(wèn)題,具體取決于調(diào)用函數(shù)的上下文。但請(qǐng)注意,您需要保留對(duì)偵聽器的引用,以便稍后將其刪除。

這是一個(gè)有和沒(méi)有bind()的例子:

var Something = function(element) {
  // |this| is a newly created object
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // undefined, as |this| is the element
  };
  this.onclick2 = function(event) {
    console.log(this.name); // 'Something Good', as |this| is bound to newly created object
  };
  element.addEventListener('click', this.onclick1, false);
  element.addEventListener('click', this.onclick2.bind(this), false); // Trick
}
var s = new Something(document.body);

另一個(gè)解決方案是使用一個(gè)特殊的函數(shù)handleEvent()來(lái)捕獲任何事件:

var Something = function(element) {
  // |this| is a newly created object
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // 'Something Good', as this is bound to newly created object
    switch(event.type) {
      case 'click':
        // some code here...
        break;
      case 'dblclick':
        // some code here...
        break;
    }
  };

  // Note that the listeners in this case are |this|, not this.handleEvent
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // You can properly remove the listeners
  element.removeEventListener('click', this, false);
  element.removeEventListener('dblclick', this, false);
}
var s = new Something(document.body);

處理對(duì)this的引用的另一種方法是向EventListener傳遞一個(gè)函數(shù),該函數(shù)調(diào)用包含需要訪問(wèn)的字段的對(duì)象的方法:

class SomeClass {

  constructor() {
    this.name = 'Something Good';
  }

  register() {
    var that = this;
    window.addEventListener('keydown', function(e) {return that.someMethod(e);});
  }

  someMethod(e) {
    console.log(this.name);
    switch(e.keyCode) {
      case 5:
        // some code here...
        break;
      case 6:
        // some code here...
        break;
    }
  }

}

var myObject = new SomeClass();
myObject.register();

舊版Internet Explorer和attachEvent

在IE 9之前的Internet Explorer版本中,您必須使用attachEvent()而不是標(biāo)準(zhǔn)addEventListener()。對(duì)于IE,我們將前面的示例修改為:

if (el.addEventListener) {
  el.addEventListener('click', modifyText, false); 
} else if (el.attachEvent)  {
  el.attachEvent('onclick', modifyText);
}

attachEvent()有一個(gè)缺點(diǎn):this的值將是window對(duì)象的引用,而不是引發(fā)它的元素。

該attachEvent()方法可以與onresize事件配對(duì)以檢測(cè)何時(shí)調(diào)整網(wǎng)頁(yè)中的某些元素的大小。專門的mselementresize事件與注冊(cè)事件處理程序的addEventListener方法配合使用時(shí),提供與onresize調(diào)整某些HTML元素大小時(shí)相同的功能。

兼容性

通過(guò)在腳本開頭使用以下代碼,您可以解決addEventListener(),removeEventListener(),Event.preventDefault(),和Event.stopPropagation()不被Internet Explorer 8支持的問(wèn)題。該代碼支持使用handleEvent()和DOMContentLoaded事件。

注意:useCapture不支持,因?yàn)镮E 8沒(méi)有任何替代方法。以下代碼僅添加了IE 8支持。此IE 8 polyfill僅適用于標(biāo)準(zhǔn)模式:需要doctype聲明。

(function() {
  if (!Event.prototype.preventDefault) {
    Event.prototype.preventDefault=function() {
      this.returnValue=false;
    };
  }
  if (!Event.prototype.stopPropagation) {
    Event.prototype.stopPropagation=function() {
      this.cancelBubble=true;
    };
  }
  if (!Element.prototype.addEventListener) {
    var eventListeners=[];
    
    var addEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var self=this;
      var wrapper=function(e) {
        e.target=e.srcElement;
        e.currentTarget=self;
        if (typeof listener.handleEvent != 'undefined') {
          listener.handleEvent(e);
        } else {
          listener.call(self,e);
        }
      };
      if (type=="DOMContentLoaded") {
        var wrapper2=function(e) {
          if (document.readyState=="complete") {
            wrapper(e);
          }
        };
        document.attachEvent("onreadystatechange",wrapper2);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper2});
        
        if (document.readyState=="complete") {
          var e=new Event();
          e.srcElement=window;
          wrapper2(e);
        }
      } else {
        this.attachEvent("on"+type,wrapper);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper});
      }
    };
    var removeEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var counter=0;
      while (counter<eventListeners.length) {
        var eventListener=eventListeners[counter];
        if (eventListener.object==this && eventListener.type==type && eventListener.listener==listener) {
          if (type=="DOMContentLoaded") {
            this.detachEvent("onreadystatechange",eventListener.wrapper);
          } else {
            this.detachEvent("on"+type,eventListener.wrapper);
          }
          eventListeners.splice(counter, 1);
          break;
        }
        ++counter;
      }
    };
    Element.prototype.addEventListener=addEventListener;
    Element.prototype.removeEventListener=removeEventListener;
    if (HTMLDocument) {
      HTMLDocument.prototype.addEventListener=addEventListener;
      HTMLDocument.prototype.removeEventListener=removeEventListener;
    }
    if (Window) {
      Window.prototype.addEventListener=addEventListener;
      Window.prototype.removeEventListener=removeEventListener;
    }
  }
})();

較舊的方式來(lái)注冊(cè)事件監(jiān)聽器

addEventListener()是隨著DOM 2 Events規(guī)范引入的。在此之前,事件監(jiān)聽器注冊(cè)如下:

// Passing a function reference — do not add '()' after it, which would call the function!
el.onclick = modifyText;

// Using a function expression
element.onclick = function() {
  // ... function logic ...
};

如果有click的話,此方法將替換元素上的現(xiàn)有click事件偵聽器。其他事件和相關(guān)的事件處理程序(如blur(onblur)和keypress(onkeypress))的行為類似。

因?yàn)樗举|(zhì)上是DOM 0的一部分,所以這種添加事件監(jiān)聽器的技術(shù)得到了廣泛的支持,并且不需要特殊的跨瀏覽器代碼。它通常用于動(dòng)態(tài)注冊(cè)事件偵聽器,除非需要額外的addEventListener()功能。

內(nèi)存問(wèn)題

var i;
var els = document.getElementsByTagName('*');


// Case 1
for(i=0 ; i<els.length ; i++){
  els[i].addEventListener("click", function(e){/*do something*/}, false);
}


// Case 2
function processEvent(e){
  /*do something*/
}

for(i=0 ; i<els.length ; i++){
  els[i].addEventListener("click", processEvent, false);
}

在上面的第一種情況中,每次迭代循環(huán)都會(huì)創(chuàng)建一個(gè)新的(匿名)處理函數(shù)。在第二種情況下,相同的先前聲明的函數(shù)被用作事件處理程序,這導(dǎo)致較小的內(nèi)存消耗,因?yàn)橹粍?chuàng)建了一個(gè)處理函數(shù)。此外,在第一種情況下,無(wú)法調(diào)用removeEventListener(),因?yàn)椴槐A魧?duì)anonymous函數(shù)的引用(或者這里,不保留循環(huán)可能創(chuàng)建的任何多個(gè)anonymous函數(shù)。);在第二種情況下,可以執(zhí)行myElement.removeEventListener("click", processEvent, false) 因?yàn)閜rocessEvent是函數(shù)引用。 

實(shí)際上,關(guān)于內(nèi)存消耗,缺乏保留函數(shù)引用不是真正的問(wèn)題;而是缺乏保持STATIC函數(shù)引用。在下面的兩個(gè)問(wèn)題情況中,都保留了函數(shù)引用,但由于它在每次迭代時(shí)重新定義,因此它不是靜態(tài)的。在第三種情況下,每次迭代都會(huì)重新分配對(duì)anonymous函數(shù)的引用。在第四種情況下,整個(gè)函數(shù)定義是不變的,但它仍然被重復(fù)定義為new(除非它被編譯器[[promote]],因此不是靜態(tài)的。因此,盡管看起來(lái)只是[[Multiple identical event listeners]],但在這兩種情況下,每次迭代都會(huì)創(chuàng)建一個(gè)新的偵聽器,它具有對(duì)處理函數(shù)的唯一引用。但是,由于函數(shù)定義本身不會(huì)改變,

同樣在這兩種情況下,由于函數(shù)引用被保留但每次添加都重復(fù)定義,上面的remove-statement仍然可以刪除一個(gè)偵聽器,但現(xiàn)在只添加了最后一個(gè)。

// For illustration only: Note "MISTAKE" of [j] for [i] thus causing desired events to all attach to SAME element

// Case 3
for(var i=0, j=0 ; i<els.length ; i++){
  /*do lots of stuff with j*/
  els[j].addEventListener("click", processEvent = function(e){/*do something*/}, false);
}

// Case 4
for(var i=0, j=0 ; i<els.length ; i++){
  /*do lots of stuff with j*/
  function processEvent(e){/*do something*/};
  els[j].addEventListener("click", processEvent, false); 
}

使用被動(dòng)偵聽器提高滾動(dòng)性能

根據(jù)規(guī)范,該passive選項(xiàng)的默認(rèn)值始終為false。但是,這引入了處理某些觸摸事件(以及其他)的事件偵聽器在嘗試處理滾動(dòng)時(shí)阻止瀏覽器的主線程的可能性,從而導(dǎo)致滾動(dòng)處理期間性能可能大大降低。

為了避免這個(gè)問(wèn)題,一些瀏覽器(具體而言,Chrome和Firefox)已經(jīng)將文檔級(jí)節(jié)點(diǎn)Window,Document和Document.body中的touchstart和touchmove事件的passive選項(xiàng)的默認(rèn)值更改為true。這可以防止調(diào)用事件偵聽器,因此在用戶滾動(dòng)時(shí)無(wú)法阻止頁(yè)面呈現(xiàn)。

注意:如果您需要知道哪些瀏覽器(或這些瀏覽器的哪些版本)實(shí)現(xiàn)了這種更改的行為,請(qǐng)參閱下面的兼容性表。

您可以通過(guò)顯式設(shè)置passiveto的值為false來(lái)覆蓋此行為,如下所示:

/* Feature detection */
var passiveIfSupported = false;

try {
  window.addEventListener("test", null, Object.defineProperty({}, "passive", { get: function() { passiveIfSupported = { passive: true }; } }));
} catch(err) {}

window.addEventListener('scroll', function(event) {
  /* do something */
  // can't use event.preventDefault();
}, passiveIfSupported );

在不支持addEventListener()的options參數(shù)的舊瀏覽器上,嘗試使用它會(huì)阻止useCapture參數(shù)的使用,而無(wú)需正確使用特性檢測(cè)。

對(duì)于基本scroll事件,您無(wú)需擔(dān)心passive的值。由于無(wú)法取消,因此事件偵聽器無(wú)法阻止頁(yè)面呈現(xiàn)。

規(guī)范

規(guī)格 狀態(tài) 注釋
DOM 
該規(guī)范中'EventTarget.addEventListener()'的定義。
Living Standard
 
DOM4 
該規(guī)范中“EventTarget.addEventListener()”的定義。
Obsolete
 
文檔對(duì)象模型(DOM)級(jí)別2事件規(guī)范 
該規(guī)范 
中“EventTarget.addEventListener()”的定義。
Obsolete
初步定義

瀏覽器兼容性

電腦端 移動(dòng)端
Chrome
Edge
Firefox
Internet Explorer
Opera
Safari
Android webview Chrome for Android
Edge Mobile Firefox for Android
Opera for Android
iOS Safari
基本支持
支持:1

支持:12 支持:1 支持:9 支持:7 支持:1
支持:1

支持:18

支持 支持:4 支持:7 支持:1
useCapture 參數(shù)可選 支持:1 支持 支持:6 支持:9 支持:11.6 支持 支持:1 支持:18 支持 支持:6 支持:11.6 支持
options對(duì)象支持的表單(第三個(gè)參數(shù)可以是Boolean,也可以是選項(xiàng),以便向后兼容) 支持:49 支持 支持:49 不支持號(hào) 支持 支持:10 支持:49 支持:49 支持 支持:49 支持 支持:10
options:capture選項(xiàng) 支持:52 支持 支持 不支持 支持 支持 支持:52 支持:52 支持 支持 支持 支持
options:once選項(xiàng) 支持:55 支持 支持:50 不支持 支持:42 支持 支持:55 支持:55 支持 支持:50 支持:42 支持
options:passive選項(xiàng) 支持:51 支持 支持 不支持 支持 支持 支持:51 支持:51 支持 支持 支持 支持
options:passive選項(xiàng)默認(rèn)為truefortouchstart和touchmoveevents 支持:55 不支持 支持:61 不支持 ? 不支持 支持:55 支持:55 不支持 支持:61 不支持
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)