javascript - true - passive addeventlistener




addEventListener vs onclick (9)

addEventListeneronclick什麼區別?

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

上面的代碼一起存放在一個單獨的.js文件中,並且它們都可以很好地工作。


JavaScript傾向於將所有東西都混合到對像中,這可能會讓它變得令人困惑。 一切都是JavaScript的方式。

本質上onclick是一個HTML屬性。 相反,addEventListener是表示HTML元素的DOM對象的一種方法。

在JavaScript對像中,一個方法僅僅是一個屬性,它具有一個作為值的函數,並且對它所附著的對象(例如使用這個對象)起作用。

在JavaScript中,由DOM表示的HTML元素將其屬性映射到其屬性。

這是人們感到困惑的地方,因為JavaScript把所有東西都融合到一個沒有間接層的容器或名稱空間中。

在一個正常的OO佈局中(至少合併了屬性/方法的命名空間),你可能會有這樣的東西:

domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))

有各種各樣的變體,例如它可以使用onload的getter / setter或屬性的HashMap,但最終這是它的樣子。 JavaScript期望知道除了其他事情之外,JavaScript消除了這種間接性。 它將domElement和屬性合併在一起。

除了兼容性,您應該使用addEventListener作為最佳實踐。 正如其他答案所討論的那樣,在這方面的差異而不是基本的方案差異我會放棄它。 從本質上講,在一個理想的世界中,你實際上只是想從HTML中使用*,但在更理想的世界中,你不應該像HTML那樣做任何事情。

為什麼今天它佔統治地位? 寫起來更快,更容易學習,並且往往只是工作。

在HTML中加載的重點是首先允許訪問addEventListener方法或功能。 通過在JS中使用它,當你可以直接應用它時,你會通過HTML。

假設你可以創造你自己的屬性:

$('[myclick]').each(function(i, v) {
     v.addEventListener('click', function() {
         eval(v.myclick); // eval($(v).attr('myclick'));
     });
});

JS所做的與此有點不同。

您可以將它等同於(對於創建的每個元素):

element.addEventListener('click', function() {
    switch(typeof element.onclick) {
          case 'string':eval(element.onclick);break;
          case 'function':element.onclick();break;
     }
});

實際的實施細節可能會因一系列微妙的變化而有所不同,這使得兩者在某些情況下略有不同,但這是它的要點。

這可以說是一種兼容性破解,你可以將一個函數固定為on屬性,因為默認情況下屬性都是字符串。


JavasSript中的'this'引用的上下文是不同的。

看下面的代碼:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

</head>
<body>
    <input id="btnSubmit" type="button" value="Submit" />
    <script>
        function disable() {
            this.disabled = true;
        }
        var btnSubmit = document.getElementById('btnSubmit');
        btnSubmit.onclick = disable();
        //btnSubmit.addEventListener('click', disable, false);
    </script>
</body>
</html>

它的功能非常簡單。 當你點擊該按鈕時,該按鈕將被自動禁用。

首先,當您嘗試以這種方式button.onclick = function(),事件button.onclick = function(), onclick事件將通過單擊按鈕觸發,但是,該按鈕不會被禁用,因為button.onclick和onclick事件之間沒有明確的綁定處理程序。 如果你調試看到'this'對象,你可以看到它指的是'window'對象。

其次,如果你評論btnSubmit.onclick = disable(); 並取消註釋//btnSubmit.addEventListener('click', disable, false); 您可以看到該按鈕被禁用,因為通過這種方式,button.onclick事件和onclick事件處理程序之間存在顯式綁定。 如果您調試到禁用功能,您可以看到'this'是指button control而不是window

這是我不喜歡JavaScript不一致的地方。 順便說一句,如果你使用jQuery( $('#btnSubmit').on('click', disable); ),它使用顯式綁定。


一個細節還沒有被注意到:現代桌面瀏覽器認為不同的按鈕是AddEventListener('click' “點擊” AddEventListener('click'默認為AddEventListener('click'onclick

  • 在Chrome 42和IE11上, onclickAddEventListener點擊左側和中間點擊。
  • 在Firefox 38上, onclick 在左鍵單擊時觸發,但AddEventListener單擊左鍵,中鍵右鍵點擊。

此外,涉及滾動游標時,跨瀏覽器的中點擊行為非常不一致:

  • 在Firefox上,中點擊事件總是會觸發。
  • 在Chrome上,如果middleclick打開或關閉滾動光標,它們將不會觸發。
  • 在IE中,它們在滾動游標關閉時觸發,但在打開時不會觸發。

還值得注意的是,對於任何鍵盤可選HTML元素(如input “單擊”事件也會在空間觸發,或者在選擇元素時進行輸入。


你可以看到,如果你有另外幾個功能的區別:

var h = document.getElementById('a');
h.onclick = donothing1;
h.onclick = donothing2;

h.addEventListener('click', donothing3);
h.addEventListener('click', donothing4);

功能2,3和4工作,但1不工作。 這是因為addEventListener不覆蓋現有的事件處理程序,而onclick覆蓋任何現有的onclick = fn事件處理程序。

當然,另一個顯著差異是onclick將始終工作,而addEventListener在版本9之前的Internet Explorer中不起作用。您可以在IE <9中使用類似的attachEvent (語法略有不同)。


兩者都是正確的,但它們本身都不是“最好的”,開發人員可能會選擇使用這兩種方法。

事件監聽器(addEventListener和IE的attachEvent)

早期版本的Internet Explorer與其他幾乎所有瀏覽器的JavaScript都有所不同。 對於小於9的版本,可以使用attachEvent [ doc ]方法,如下所示:

element.attachEvent('onclick', function() { /* do stuff here*/ });

在大多數其他瀏覽器(包括IE 9及以上版本)中,您可以使用addEventListener [ doc ],如下所示:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

使用這種方法( DOM Level 2事件 ),您可以將理論上無限數量的事件附加到任何單個元素。 唯一的實際限制是客戶端內存和其他性能問題,這對每個瀏覽器都是不同的。

上面的例子表示使用匿名函數[ doc ]。 您還可以使用函數reference [ doc ]或閉包[ doc ]添加事件偵聽器:

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

addEventListener另一個重要特性是最終參數,它控制偵聽器如何對冒泡事件做出反應[ doc ]。 我在例子中傳遞了錯誤,這可能是95%的用例的標準。 attachEvent沒有等價的參數,或者使用內聯事件時。

內聯事件(HTML onclick =“”property and element.onclick)

在支持javascript的所有瀏覽器中,您可以將事件偵聽器內聯,即在HTML代碼中正確表示。 你可能已經看到了這個:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

大多數有經驗的開發人員避開這種方法,但它確實完成了工作; 它簡單直接。 你不能在這裡使用閉包或匿名函數(雖然處理程序本身是一種匿名函數),而你對范圍的控制是有限的。

你提到的另一種方法:

element.onclick = function () { /*do stuff here */ };

...相當於內聯javascript,不同之處在於您可以更好地控制範圍(因為您在編寫腳本而不是HTML),並且可以使用匿名函數,函數引用和/或閉包。

內聯事件的一個明顯缺點是,與上述事件監聽器不同,您可能只分配了一個內聯事件。 內聯事件存儲為元素[ doc ]的屬性/屬性,這意味著它可以被覆蓋。

使用上面HTML中的示例<a>

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

...當你點擊這個元素時,你只會看到“Did stuff#2” - 你用第二個值覆蓋了onclick屬性的第一個賦值,並且你也覆蓋了原來的內聯HTML onclick屬性。 看看這裡: http://jsfiddle.net/jpgah/ : http://jsfiddle.net/jpgah/

哪個最好?

問題在於瀏覽器的兼容性和必要性。 您目前是否需要為一個元素附加多個事件? 你會在未來嗎? 賠率是,你會的。 attachEvent和addEventListener是必需的。 如果不是的話,一個內聯事件將會訣竅。

jQuery和其他JavaScript框架在通用模型中封裝DOM級別2事件的不同瀏覽器實現,因此您可以編寫跨瀏覽器兼容的代碼,而無需擔心IE作為反叛者的歷史記錄。 與jQuery相同的代碼,所有跨瀏覽器和準備搖滾:

$(element).on('click', function () { /* do stuff */ });

儘管如此,不要耗盡這個框架。 您可以輕鬆地推出自己的小工具來照顧舊版瀏覽器:

function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

// example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { alert('hi!'); }
);

試試看: http://jsfiddle.net/bmArj/ : http://jsfiddle.net/bmArj/

考慮到所有這些因素,除非您正在查看的腳本以某種其他方式考慮了瀏覽器差異(代碼中未顯示您的問題),那麼使用addEventListener的部分在IE版本少於9的情況下將不起作用。

文件和相關閱讀


在這個答案中,我將描述定義DOM事件處理程序的三種方法。

element.addEventListener()

代碼示例:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>

element.addEventListener()具有多個優點:

  • 允許您註冊無限的事件處理程序,並使用element.removeEventListener()將其刪除。
  • useCapture參數,它表示您是否想要在捕獲或冒泡階段處理事件。 請參閱: 無法理解addEventListener中的useCapture屬性
  • 關心語義 。 基本上,它使註冊事件處理程序更加明確。 對於初學者來說,函數調用很明顯會發生某些事情 ,而將事件分配給DOM元素的某個屬性至少不直觀。
  • 允許您分隔文檔結構(HTML)和邏輯(JavaScript) 。 在小型Web應用程序中,它似乎並不重要,但它對於任何更大的項目都很重要。 維護一個分離​​結構和邏輯的項目比一個沒有的項目要容易得多。
  • 用正確的事件名稱消除混淆。 由於使用內聯事件偵聽器或將事件偵聽器分配給DOM元素的.onevent屬性,許多沒有經驗的JavaScript程序員認為事件名稱是例如onclickonloadon 不是事件名稱的一部分 。 正確的事件名稱是clickload ,這就是事件名稱傳遞給.addEventListener()
  • 幾乎所有瀏覽器都可以使用 如果您仍然需要支持IE <= 8,則可以使用MDN中的polyfill

element.onevent = function() {} (例如onclickonload

代碼示例:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>

這是一種在DOM 0中註冊事件處理程序的方法。現在不鼓勵它,因為它:

  • 允許您註冊一個事件處理程序。 另外刪除指定的處理程序並不直觀,因為要刪除使用此方法分配的事件處理程序,必須將onevent屬性恢復為其初始狀態(即null )。
  • 不適當地回應錯誤 。 例如,如果您錯誤地將一個字符串分配給window.onload ,例如: window.onload = "test"; 它不會拋出任何錯誤。 你的代碼無法正常工作,並且很難找出原因。 但是, .addEventListener()會拋出錯誤(至少在Firefox中): TypeError:EventTarget.addEventListener的參數2不是對象
  • 如果您想在捕獲或冒泡階段處理事件,不提供選擇方法。

內聯事件處理程序( onevent HTML屬性)

代碼示例:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

類似於element.onevent ,現在不鼓勵。 除了element.onevent的問題之外,它還包括:

  • 是一個潛在的安全問題 ,因為它使XSS更加有害。 現在,網站應發送適當的Content-Security-Policy HTTP標頭來阻止內聯腳本,並允許僅來自受信任域的外部腳本。 請參閱內容安全策略如何工作?
  • 分離文檔結構和邏輯
  • 如果您使用服務器端腳本生成頁面,並且例如您生成了100個鏈接,每個鏈接都具有相同的內聯事件處理程序,那麼您的代碼將比僅定義一次事件處理程序的時間長得多。 這意味著客戶將不得不下載更多的內容,結果你的網站會變慢。

也可以看看


據我所知,DOM“加載”事件的作用仍然非常有限。 這意味著它只會觸發window objectimages<script>元素。 直接onload分配也是如此。 這兩者之間沒有技術上的區別。 可能是.onload =有更好的跨瀏覽器可用性。

但是,您無法將load event分配給<div><span>元素或其他元素。


根據MDN ,差異如下:

的addEventListener:

EventTarget.addEventListener()方法將指定的與EventListener兼容的對象添加到其調用的EventTarget上指定事件類型的事件偵聽器列表。 事件目標可以是文檔中的元素,文檔本身,窗口或任何其他支持事件的對象(如XMLHttpRequest)。

的onclick:

onclick屬性返回當前元素上的click事件處理程序代碼。 當使用click事件觸發某個動作時,還可以考慮將相同的動作添加到keydown事件中,以允許不使用鼠標或觸摸屏的人使用同一動作。 語法element.onclick = functionRef; 其中functionRef是一個函數 - 通常是在別處聲明的函數或函數表達式的名稱。 有關詳細信息,請參閱“JavaScript指南:函數”。

如您在下面的代碼中看到的,還有一種使用中的語法差異:

的addEventListener:

// 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);

的onclick:

function initElement() {
    var p = document.getElementById("foo");
    // NOTE: showAlert(); or showAlert(param); will NOT work here.
    // Must be a reference to a function name, not a function call.
    p.onclick = showAlert;
};

function showAlert(event) {
    alert("onclick Event detected!");
}

雖然onclick適用於所有瀏覽器,但addEventListener不適用於Internet Explorer的舊版本,該版本使用attachEvent代替。

onclick的缺點是只能有一個事件處理程序,而另外兩個會觸發所有已註冊的回調。





addeventlistener