摘要:歡迎來我的專欄查看系列文章。無論的源碼簡單或者復雜,有一點可以肯定,致力于解決瀏覽器的兼容問題,最終是服務于使用者。參考源碼分析事件體系結構庫原生事件詳解本文在上的源碼地址,歡迎來。
歡迎來我的專欄查看系列文章。
前面一章,大概是一個總覽,介紹了事件綁定的初衷和使用,通過了解,知道其內部是一個什么樣的流程,從哪個函數到哪個函數。無論 jQuery 的源碼簡單或者復雜,有一點可以肯定,jQuery 致力于解決瀏覽器的兼容問題,最終是服務于使用者。
一些遺留問題前面介紹 bind、delegate 和它們的 un 方法的時候,經提醒,忘記提到一些內容,卻是我們經常使用的。比如 $("body").click,$("body").mouseleave等,它們是直接定義在原型上的函數,不知道怎么,就把它們給忽略了。
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); }; } );
這個構造也是十分巧妙的,這些方法組成的字符串通過 split(" ") 變成數組,而后又通過 each 方法,在原型上對應每個名稱,定義函數,這里可以看到,依舊是 on,還有 targger:
jQuery.fn.extend( { trigger: function(type, data){ return this.each(function (){ // // 依舊是 event 對象上的方法 jQuery.event.trigger(type, data, this); }) } } )
還缺少一個 one 方法,這個方法表示綁定的事件同類型只執行一次,.one():
jQuery.fn.extend( { one: function( types, selector, data, fn ) { // 全局 on 函數 return on( this, types, selector, data, fn, 1 ); }, } );DOM 事件知識點
發現隨著 event 源碼的不斷的深入,我自己出現越來越多的問題,比如沒有看到我所熟悉的 addEventListener,還有一些看得很迷糊的 events 事件,所以我決定還是先來看懂 JS 中的 DOM 事件吧。
早期 DOM 事件在 HTML 的 DOM 對象中,有一些以 on 開頭的熟悉,比如 onclick、onmouseout 等,這些就是早期的 DOM 事件,它的最簡單的用法,就是支持直接在對象上以名稱來寫函數:
document.getElementsByTagName("body")[0].onclick = function(){ console.log("click!"); } document.getElementsByTagName("body")[0].onmouseout = function(){ console.log("mouse out!"); }
onclick 函數會默認傳入一個 event 參數,表示觸發事件時的狀態,包括觸發對象,坐標等等。
這種方式有一個非常大的弊端,就是相同名稱的事件,會前后覆蓋,后一個 click 函數會把前一個 click 函數覆蓋掉:
var body = document.getElementsByTagName("body")[0]; body.onclick = function(){ console.log("click1"); } body.onclick = function(){ console.log("click2"); } // "click2" body.onclick = null; // 沒有效果DOM 2.0
隨著 DOM 的發展,已經來到 2.0 時代,也就是我所熟悉的 addEventListener 和 attachEvent(IE),JS 中的事件冒泡與捕獲。這個時候和之前相比,變化真的是太大了,MDN addEventListener()。
變化雖然是變化了,但是瀏覽器的兼容卻成了一個大問題,比如下面就可以實現不支持 addEventListener 瀏覽器:
(function() { // 不支持 preventDefault if (!Event.prototype.preventDefault) { Event.prototype.preventDefault=function() { this.returnValue=false; }; } // 不支持 stopPropagation if (!Event.prototype.stopPropagation) { Event.prototype.stopPropagation=function() { this.cancelBubble=true; }; } // 不支持 addEventListener 時候 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雖然不支持 addEventListener 的瀏覽器可以實現這個功能,但本質上還是通過 attachEvent 函數來實現的,在理解 DOM 早期的事件如何來建立還是比較捉急的。
addEvent 庫addEvent庫的這篇博客發表于 2005 年 10 月,所以這篇博客所講述的 addEvent 方法算是經典型的,就連 jQuery 中的事件方法也是借鑒于此,故值得一提:
function addEvent(element, type, handler) { // 給每一個要綁定的函數添加一個標識 guid if (!handler.$$guid) handler.$$guid = addEvent.guid++; // 在綁定的對象事件上創建一個事件對象 if (!element.events) element.events = {}; // 一個 type 對應一個 handlers 對象,比如 click 可同時處理多個函數 var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // 如果 onclick 已經存在一個函數,拿過來 if (element["on" + type]) { handlers[0] = element["on" + type]; } } // 防止重復綁定,每個對應一個 guid handlers[handler.$$guid] = handler; // 把 onclick 函數替換成 handleEvent element["on" + type] = handleEvent; }; // 初始 guid addEvent.guid = 1; function removeEvent(element, type, handler) { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } // 感覺后面是不是要加個判斷,當 element.events[type] 為空時,一起刪了 }; function handleEvent(event) { // grab the event object (IE uses a global event object) event = event || window.event; // 這里的 this 指向 element var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { // 這里有個小技巧,為什么不直接執行,而是先綁定到 this 后執行 // 是為了讓函數執行的時候,內部 this 指向 element this.$$handleEvent = handlers[i]; this.$$handleEvent(event); } };如果能將上面 addEvent 庫的這些代碼看懂,那么在看 jQuery 的 events 源碼就明朗多了。
還有一個問題,所謂事件監聽,是將事件綁定到父元素或 document 上,子元素來響應,如何實現?
要靠 event 傳入的參數 e:
var body = document.getElementsByTagName("body")[0]; body.onclick = function(e){ console.log(e.target.className); }這個 e.target 對象就是點擊的那個子元素了,無論是捕獲也好,冒泡也好,貌似都能夠模擬出來。接下來,可能要真的步入正題了。
總結感覺事件委托的代碼還是相當復雜的,我自己也啃了好多天,有那么一點點頭緒,其中還有很多模模糊糊的知識點,只是覺得,存在就是牛逼的,我看不懂,但不代表它不牛逼。
參考jQuery 2.0.3 源碼分析 事件體系結構
addEvent庫
MDN EventTarget.addEventListener()
原生JavaScript事件詳解本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81779.html
摘要:教程所示圖片使用的是倉庫圖片,網速過慢的朋友請移步系列教程十二處理第三方庫原文地址。因為正式項目中,由于需要的依賴過多,掛載到對象的庫,很容易發生命名沖突問題。會先從安裝的包中查找是否有符合的庫。證明在中使用的和都成功指向了庫。 教程所示圖片使用的是 github 倉庫圖片,網速過慢的朋友請移步《webpack4 系列教程(十二):處理第三方 JavaScript 庫》原文地址。或者來...
摘要:專題系列共計篇,主要研究日常開發中一些功能點的實現,比如防抖節流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數組合專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。 JavaScript 專題之從零實現 jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現一個 jQuery 的 ext...
摘要:專門為事件建立一個有問題,直接退出如果是一個事件處理對象,且有屬性。參考源碼分析事件體系結構解密事件核心綁定設計一解密事件核心委托設計二本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 通過前面一章對于 addEvent 庫的介紹,它的兼容性超級棒,據說對于 IE4、5 都有很好的兼容性,這和 jQuery 的原理是一致的,而在 jQuery 中,有一個對象與其相對應,那就是...
摘要:新增事件部分講完了后我們最后實現個方法關于就常用的就種一個是取值一個是賦值我們通過判斷的個數是取值還是賦值賦值很容易我們就用最簡單的辦法直接設置如果是取值那我們就要做個判斷因為和的取法是不一樣的還有一種可能性是當元素的為的時候直接取是取不 Lesson-11 新增width,height,extend 事件部分講完了后,我們最后實現3個方法. width : function(w) ...
摘要:新增事件部分講完了后我們最后實現個方法關于就常用的就種一個是取值一個是賦值我們通過判斷的個數是取值還是賦值賦值很容易我們就用最簡單的辦法直接設置如果是取值那我們就要做個判斷因為和的取法是不一樣的還有一種可能性是當元素的為的時候直接取是取不 Lesson-11 新增width,height,extend 事件部分講完了后,我們最后實現3個方法. width : function(w) ...
閱讀 3140·2021-09-28 09:36
閱讀 3685·2021-09-08 09:45
閱讀 1793·2021-09-01 10:43
閱讀 3470·2019-08-30 12:44
閱讀 3345·2019-08-29 17:25
閱讀 1370·2019-08-29 11:03
閱讀 1992·2019-08-26 13:36
閱讀 693·2019-08-23 18:24