搜尋
首頁web前端js教程深入分析原生JavaScript事件_基礎知識

 JQuery這種Write Less Do More的框架,用多了難免會對原生js眼高手低。

     小菜其實不想寫這篇博客,貌似很初級的樣子,但是看到網絡上連原生js事件綁定和解除都說不明白,還是決定科普一下了。

     先聲明,小菜懂的也不是很多,只是把我的思路和大家分享一下。

DOM0事件模型

     事件模型不斷發展,早期的事件模型稱為DOM0等級。

     DOM0事件模型,所有的瀏覽器都支援。

     直接在dom物件上註冊事件名稱,就是DOM0寫法,例如:

複製程式碼 程式碼如下:

document.getElementById("test").onclick = function(e){};

     意思是註冊一個onclick事件。當然,它和這種寫法是一個意思:

複製程式碼 程式碼如下:

document.getElementById("test")["onmousemove"] = function(e){};

     這沒什麼,只不過是兩種存取js物件屬性的方法,[]的形式主要是為了解決屬性名不是合法的標識符,例如:object.123肯定報錯,但是object["123"]就避免了這個問題,同時,[]的寫法,也把js寫活了,用字串表示屬性名稱,可以在運行時動態綁定事件。

     言歸正傳,事件被觸發時,會預設傳入一個參數e,表示事件對象,透過e,我們可以獲得許多有用的信息,例如點擊的座標、具體觸發該事件的dom元素等等。

     以DOM0為基礎的事件,對於同一個dom節點而言,只能註冊一個,後邊註冊的同種事件會涵蓋先前註冊的事件。例如:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert("ok");
 };
 btn["onmousemove"] = function(e){
   alert("ok1");
 };

     結果會輸出ok1。

     接下來再說一次this。事件觸發時,this就是指該事件在哪個dom物件上觸發。例如:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 btn.onmousemove = function(e){
   alert(this.id);
 };

     結果輸出test。因為事件就是在id為test的dom節點上註冊的,所以事件觸發時,this當然代表這個dom節點,可以理解為事件是被這個dom節點呼叫的。

     所以,想解除事件就相當簡單了,只需要再註冊一次事件,把數值設為null,例如:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 btn.onclick = function(e){
   alert("ok");
 };
 btn.onclick = null;

     原則是最後註冊的事件要覆蓋之前的,最後一次註冊事件設定成null,也就解除了事件綁定。

     事情還沒結束,DOM0事件模型也牽涉到直接寫在html中的事件。例如:

複製程式碼 程式碼如下:


     以這種方式註冊的事件,同樣遵循覆蓋原則,同樣只能註冊一個,最後一個生效。

     差異就是,這樣註冊的事件,相當於動態呼叫函數(有點eval的意思),因此不會傳入event對象,同時,this指向的是window,不再是觸發事件的dom對象。

DOM2事件模型

     DOM2事件模型相對於DOM0,小菜僅了解以下兩點:

          ·  DOM2支援同一dom元素註冊多個同種事件。

          ·  DOM2新增了捕捉與冒泡的概念。

     DOM2事件透過addEventListener和removeEventListener管理,當然,這是標準。

     但IE8及其以下版本瀏覽器,自娛自樂,搞出了對應的attachEvent和detachEvent,由於小菜才疏學淺,本文不做討論。

     addEventListener當然就是註冊事件,她有三個參數,分別為:"事件名稱", "事件回呼", "捕捉/冒泡"。舉例:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 btn.addEventListener("click", function(e){
   alert("ok");
 }, false);

     事件名稱就不用多說了,相較於DOM0,去掉了前邊的on而已。

     事件回呼也很容易理解,事件觸發了總得通知你吧!回呼時和DOM0一樣,也會預設傳入一個event參數,同時this是指觸發該事件的dom節點。

     最後一個參數是布林型,true代表擷取事件,false代表冒泡事件。其實很好理解,先來個示意圖:

     意思是說,某個元素觸發了某個事件,最先得到通知的是window,然後是document,依次而入,直到真正觸發事件的那個元素(目標元素)為止,這個過程就是捕獲。接下來,事件會從目標元素開始起泡,再依序而出,直到window物件為止,這個過程就是冒泡。

     為什麼要這樣設計?這似乎是由於深厚的歷史淵源,小菜也不怎麼了解,就不亂說了。

     由此可看出,捕捉事件比冒泡事件先觸發。

     假設有這樣的html結構:

複製程式碼 程式碼如下:

 

  

 

     然後我們在外層div上註冊兩個click事件,分別是捕捉事件和冒泡事件,程式碼如下:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 //捕獲事件
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, true);
 //冒泡事件
 btn.addEventListener("click", function(e){
   alert("ok");
 }, false);

     最後,點選內層的div,先彈出ok1,然後彈出ok。結合上邊的原理圖,外層div相當於圖中的body,內層div相當於圖中最下邊的div,證明了捕獲事件先執行,然後執行冒泡事件。

     為什麼要強調點選內層的div呢?因為真正觸發事件的dom元素,必須是內層的,外層dom元素才有機會模擬捕捉事件和冒泡事件,從原理圖上就看出了。

     如果在真正觸發事件的dom元素上註冊捕獲事件和冒泡事件呢?

     html結構同上,js程式碼如下:

複製程式碼 程式碼如下:

 var btnInner = document.getElementById("testInner");
 //冒泡事件
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, false);
 //捕獲事件
 btnInner.addEventListener("click", function(e){
   alert("ok1");
 }, true);

     當然還是點選內層div,結果是先彈出ok,再彈出ok1。理論上應該先觸發捕獲事件,也就是先彈出ok1,但這裡比較特殊,因為我們是在真正觸發事件的dom元素上註冊的事件,相當於在圖中的div上註冊,由圖可以看出真正觸發事件的dom元素,是捕捉事件的終點,是冒泡事件的起點,所以這裡就不區分事件了,哪個先註冊,就先執行哪個。本例中,冒泡事件先註冊,所以先執行。

     這個道理適用於多個同種事件,比如說一下子註冊了3個冒泡事件,那麼執行順序就按照註冊的順序來,先註冊先執行。例如:

複製程式碼 程式碼如下:

 var btnInner = document.getElementById("testInner");
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, false);
 btnInner.addEventListener("click", function(e){
   alert("ok1");
 }, false);
 btnInner.addEventListener("click", function(e){
   alert("ok2");
 }, false);

     結果當然依序彈出ok、ok1、ok2。

     為了進一步理解事件模型,還有一種場景,假如說外層div和內層div同時註冊了捕獲事件,那麼點擊內層div時,外層div的事件一定是先觸發的,代碼如下:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 var btnInner = document.getElementById("testInner");
 btnInner.addEventListener("click", function(e){
   alert("ok");
 }, true);
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, true);

     結果是先彈出ok1。

     假如外層div和內層div都是註冊的冒泡事件,點選內層div時,一定是內層div事件先執行,原理相同。

     細心的讀者會發現,對於div嵌套的情況,如果點擊內層的div,外層的div也會觸發事件,這貌似會有問題!

     點選的明明是內層div,但外層div的事件也觸發了,這的確是個問題。

     其實,事件觸發時,會預設傳入一個event對象,前邊提過了,這個event對像上有一個方法:stopPropagation,透過此方法,可以阻止冒泡,這樣外層div就接收不到事件了。程式碼如下:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 var btnInner = document.getElementById("testInner");
 btn.addEventListener("click", function(e){
   alert("ok1");
 }, false);
 btnInner.addEventListener("click", function(e){
   //阻止冒泡
 e.stopPropagation();
   alert("ok");
 }, false);

     終於要說怎麼解除事件了。解除事件語法:btn.removeEventListener("事件名稱", "事件回呼", "擷取/冒泡");

     這和綁定事件的參數一樣,詳細說明下:

          ·  事件名稱,即說明解除哪個事件唄。

          ·  事件回呼,且是一個函數,而這個函數必須與註冊事件的函數是同一個。

          ·  事件類型,布林值,此必須與註冊事件時的類型一致。

     也就是說,名稱、回呼、類型,三者共同決定解除哪個事件,缺一不可。舉例:

複製程式碼 程式碼如下:

 var btn = document.getElementById("test");
 //將回呼儲存在變數中
 var fn = function(e){
   alert("ok");
 };
 //綁定
 btn.addEventListener("click", fn, false);
 //解除
 btn.removeEventListener("click", fn, false);

     若要註冊過的事件能夠解除,必須將回呼函數儲存起來,否則無法解除。

DOM0與DOM2混用

     事情本來就很亂了,這又來個混合使用,還讓不讓人活了。 。 。

     別怕,混合使用完全沒問題,DOM0模型和DOM2模型各自遵循自己的規則,互不影響。

     整體來說,依然是哪個先註冊,哪個先執行,其他就沒什麼了。

後記

     至此,原生js事件已經講的差不多了,小菜僅知道這些而已,歡迎讀者補充其他知識點。

     在實際應用中,真正的行家不會傻傻的真的註冊這麼多事件,一般情況下,只需在最外層dom元素註冊一次事件,然後通過捕獲、冒泡機制去找到真正觸發事件的dom元素,最後根據觸發事件的dom元素提供的資訊去呼叫回呼。

     也就是說,行家會自己管理事件,而不依賴瀏覽器去管理,這樣即可以提高效率,又保證了兼容性,JQuery不就是這麼做的嘛~

     好了,教學到此結束,希望對讀者有幫助!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具