一步步學習javascript基礎篇(8):細說事件

来源:http://www.cnblogs.com/zhaopei/archive/2016/01/11/javascript_event.html
-Advertisement-
Play Games

終於學到事件了,不知道為何聽到“事件”就有一種莫名的興奮。可能是之前的那些知識點過於枯燥無味吧,說起事件感覺頓時高大上了。今天我們就來好好分析下這個高大上的東西。 可以說,如果沒有事件我們的頁面就只能閱讀了。有了事件,我們可以通過鍵盤或是滑鼠和頁面交互了,通過我們不同的操作頁面給出不同的響應。 ...


終於學到事件了,不知道為何聽到“事件”就有一種莫名的興奮。可能是之前的那些知識點過於枯燥無味吧,說起事件感覺頓時高大上了。今天我們就來好好分析下這個高大上的東西。

可以說,如果沒有事件我們的頁面就只能閱讀了。有了事件,我們可以通過鍵盤或是滑鼠和頁面交互了,通過我們不同的操作頁面給出不同的響應。好了,開始我們今天的分析吧。

DOM0級事件處理方式

什麼是DOM0級?

其實世上本來沒有DOM0級,叫的人多了就有了DOM0級。

在1998 年 10 月 DOM1級規範成為 W3C 的推薦標準,在此之前的實現我們就習慣稱為DOM0級,其實本是沒有這個標準的。

<input type="button" value="but" id="but" />
<script type="text/javascript">
    document.getElementById("but").onclick = function () {
        alert("點擊了按鈕1");
    }
    document.getElementById("but").onclick = function () {
        alert("點擊了按鈕2");
    } 
</script>

上面代碼,我們發現點擊按鈕時,僅僅只彈出了“點擊了按鈕2”。上一個定義的方法被覆蓋了。這種會覆蓋上一次事件定義的方式我們稱為DOM0級事件。

如果我們使用Jquery來添加事件的話:

<script src="../Scripts/jquery-1.8.2.js"></script>
<input type="button" value="but" id="but" />
<script type="text/javascript">
    $("#but").click(function () {
        alert("點擊了按鈕1");
    });
    $("#but").click(function () {
        alert("點擊了按鈕2");
    });

我們會發現依次彈出了“點擊了按鈕1”,“點擊了按鈕2”,這是怎麼做到的?為什麼沒有覆蓋上一次的定義,我猜應該是使用到了DOM2級事件機制。(我沒有看過Jquery的源碼,暫時還看不懂)。

DOM2級事件處理方式

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").addEventListener("click", function () {
        alert("點擊了按鈕1");
    });
    document.getElementById("but").addEventListener("click", function () {
        alert("點擊了按鈕2");
    });        
</script>

如此通過元素對象的addEventListener添加的方法就是2級事件。這裡需要註意,與0級事件不同的是事件名前面不能帶“on”了。點擊按鈕彈出的結果和前面的Jquery添加方式一樣。

有人可能要問了,怎麼沒有DOM1級事件。我能說的是沒有就是沒有,沒有為什麼。在確定DOM1級標準的時候不需要擴展事件定義機制,DOM0級的事件就夠用了。

我們剛纔通過2級事件添加了方法,那麼如果我們想要刪除其中的一個怎麼辦。如果是上面的那種匿名方法,我可以很明確的告訴你沒辦法移除。下麵我們來說說可以移除的添加方式吧:

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").addEventListener("click", fun1);//給click事件添加方法fun1
    document.getElementById("but").addEventListener("click", fun2);//給click事件添加方法fun2

    function fun1() {
        alert("點擊了按鈕1");
    }
    function fun2() {
        alert("點擊了按鈕2");
    }

    document.getElementById("but").removeEventListener("click", fun1);//給click事件移除方法fun1
</script>

如此就通過removeEventListener方法進行移除操作了。

以上只是DOM2級的標準實現,當然除了IE這個怪胎非得當攪屎棍。在IE下,有同效的實現函數:

<input type="button" value="but" id="but" />
<script type="text/javascript">      
    document.getElementById("but").attachEvent("onclick", fun1, false);//給click事件添加方法fun1
    document.getElementById("but").attachEvent("onclick", fun2, false);//給click事件添加方法fun2

    function fun1() {
        alert("點擊了按鈕1");
    }
    function fun2() {
        alert("點擊了按鈕2");
    }

    document.getElementById("but").detachEvent("onclick", fun1);//給click事件移除方法fun1

註意:attachEvent() 和 detachEvent() 替換了addEventListener()和removeEventListener(),且第一個參數是事件名前面加了"on"。

DOM3級事件

可能有人覺得很奇怪,哪來的DOM3級事件啊。其實上面我們說的DOM0級和DOM2級事件說的是事件的處理方式而已,而這裡說的DOM3級事件是說的在DOM3級中新增的一些事件。

至於DOM1級事件,那我就真的沒聽過。

DOM3級事件是在DOM2級事件的基礎上重新定義了或是新增了某些事件。如滑鼠事件:

DOM2有,click、mousedown、mousemove、mouseout、mouseover、mouseup
而DOM3級中卻有,click、dblclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup

(其中dblclick、mouseenter、mouseleave是DOM3中新增的)
DOM3級事件實現方式可以用DOM0和DOM2級中的方式,只是新增了寫事件類型。這裡就不一一列舉了。

事件冒泡

什麼是事件冒泡?我們先來看個例子。

<div onclick="divfun();" style="border:1px dashed red;padding:50px">
    <span onclick="spanfun();" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input type="button" value="but" onclick="butfun();" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    function butfun() {
        alert("按鈕被點擊了");
    }
    function spanfun() {
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

一個div包了一個span,然後span裡面包了一個button。我們在點擊按鈕的時候會先觸發按鈕事件,然後觸發span的點擊事件,然後觸發div的點擊事件。這就是事件冒泡。(使用DOM0級事件預設是事件冒泡方式

效果圖:

示意圖:

事件捕獲

什麼是事件捕獲?其實就是事件冒泡的逆向。

那我們怎麼實現這個效果呢?我們可以通過DOM2級事件。上面我們已經簡單的講解過了DOM2級事件的實現方式

通過addEventListener和removeEventListener給事件添加和刪除函數。上面我們講addEventListener的時候如果你再回頭看看,我們只給了兩個參數,第一個是事件名,第二個是要添加的方法,其實還有第三個參數一個布爾值用來表示事件流方向(true為事件捕獲方向,false為事件冒泡方向)。那麼我們完全可以通過DOM2級事件來實現事件捕獲的效果,如:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    document.getElementById("mydiv").addEventListener("click", divfun, true);
    document.getElementById("mysapn").addEventListener("click", spanfun, true);
    document.getElementById("mybut").addEventListener("click", butfun, true);

    function butfun() {
        alert("按鈕被點擊了");
    }
    function spanfun() {
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

效果圖:

同樣,我們也可以通過DOM2級事件實現事件冒泡,就上面的代碼僅僅只需要把addEventListener的第三那個參數改成false就可以了,有興趣的同學可以自己試試。

然後IE這個攪屎棍又開始不服了,我就不實現事件捕獲你能把我怎麼著。IE中等效實現的attachEvent的根本就沒給第三個參數,所以為了相容,我們一般只用事件冒泡(IE只支持事件冒泡)。

事件冒泡的使用

  • 取消事件冒泡

通過上面,我們知道只要點擊了按鈕,那麼按鈕的上層元素中的點擊事件都會觸發。那我們會想如果我TM就只想點擊某個元素的時候才 觸發,不想讓它往上冒怎麼辦,請看下麵:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    //第三個參數是false,那麼就是事件冒泡了
    document.getElementById("mydiv").addEventListener("click", divfun, false);
    document.getElementById("mysapn").addEventListener("click", spanfun, false);
    document.getElementById("mybut").addEventListener("click", butfun, false);

    function butfun(event) {
        event.stopPropagation();//在點擊按鈕時,取消事件冒泡
        alert("按鈕被點擊了");
    }
    function spanfun() {
        //這裡沒有取消事件冒泡,所以點擊span的時候還是會繼續冒泡到div
        alert("span被點擊了");
    }
    function divfun() {
        alert("div被點擊了");
    }
</script>

效果圖:

您如果仔細看了效果圖,那麼你會發現。點擊按鈕的時候並沒有冒泡,而點擊span的時候還是冒泡了。那是因為我們代碼裡面在按鈕事件的方法裡面加了 event.stopPropagation()//取消冒泡 。

  • 事件委托

既然可以如此,我們可以在每個事件方法裡面都加上取消冒泡,那麼所有的元素都只實現自己的事件對應的方法了。我們發現這個事件冒泡反而把事情搞麻煩了,好好的一個元素對應一個事件幹嘛要冒泡啊,還要手動去取消冒泡。既然有這個東西,它總是有它的作用的。我們看到上面我們定義事件方法時,取到了每個元素,然後給每個元素定義方法。那我們可以通過事件冒泡定義一個方法來實現嗎,先看看下麵的代碼:

<div id="mydiv" style="border:1px dashed red;padding:50px">
    <span id="mysapn" style="border: 1px dashed #00ff21; padding: 30px; ">
        <input id="mybut" type="button" value="but" style="border: 1px dashed #0094ff" />
    </span>
</div>
<script type="text/javascript">
    //第三個參數是false,那麼就是事件冒泡了
    document.getElementById("mydiv").addEventListener("click", divfun, false);   function divfun(event) {
        var targetID = event.target.id 
        if (targetID == "mybut") {
            alert("按鈕被點擊了");
        } else if (targetID == "mysapn") {
            alert("span被點擊了"); 
        } else if (targetID == "mydiv") {
            alert("div被點擊了"); 
        } 
    }
</script>

 

效果圖:

仔細觀察的你,會發現我們點擊每個元素會觸發對應消息。這就是我們上面為每個元素添加方法然後取消冒泡同樣的效果。那麼我們再來分析下實現代碼,會發現這裡反而是使用了冒泡。

 event.target//返回事件的目標節點(觸發該事件的節點)  var targetID = event.target.id //返回事件的目標節點的id(觸發該事件的節點的Id) 

因為我們為最外面的div添加了事件的方法,所以我們在點擊按鈕的時候會依次觸發按鈕、span、div的點擊事件,然按鈕和span都沒有定義事件方法,所以不管是點擊按鈕、span還是div都會冒泡到div的點擊事件,然後我們就可以根據上面的target屬性來得知到底是由那個節點觸發的。請看示意圖:

有人會這,這麼麻煩有什麼好處呢?我們仔細看看這個通過冒泡實現的個節點點擊事件,你有沒有發現我們僅僅只是通過getElementById取了一個最外層的div元素,且我們也僅僅只用了一個方法(雖然方法裡面的邏輯會更加複雜點)。這隻是3個元素,如果有30個呢?甚至上百個呢?我們只定義最外層的元素,這樣就減少了大量的DOM引用了(這樣就直接減少了檢索元素需要花的時間),同時也可以減少記憶體的占用。直接提升了性能。(雖然很多時候我們不會這樣來定義事件,我自己就很少這樣來定義事件,可能是習慣問題吧。>_<

 

這是學習記錄,不是教程。文中錯誤難免,您可以指出錯誤,但請不要言辭刻薄。

原文首鏈:http://www.haojima.net/zhaopei/531.html

本文已同步至目錄索引:一步步學習javascript

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡使用的是mysql Ver 14.14 Distrib 5.6.19, for Linux (i686) using EditLine wrapper一、mysql目錄文件ibdata1:系統表空間 包含數據字典、回滾日誌/undolog等(insert buffer segment/doubl...
  • Oracle 資料庫中 SQL 分析的主要優勢Oracle 資料庫中分析功能和特性提供以下主要優勢:1. 提高開發人員產能 — 開發人員可以通過更清晰、更簡潔的 SQL 代碼執行複雜分析。現在可以使用一條 SQL 語句表示覆雜任務,編寫和維護速度更快、效率更高。 2. 提高查詢速度 — 資料庫中分析...
  • 色溫色溫是表示光源光譜質量最通用的指標。 GPUImage中我們通過GPUImageWhiteBalanceFilter來實現 頂點著色uniform sampler2D inputImageTexture;varying highp vec2 textureCoordinate; unif...
  • 寫界面可以說是每位移動應用開發者的基本功,也是一位合格移動應用開發者繞不過去的坎。但就如不是每一位開發者都能夠成為合格的開發者一樣,本人在 不同的團隊中發現,甚少有人能夠編寫出合格的UI代碼;而非常奇怪的是,在很多的開發者論壇上看到我們移動開發者更多關註於某個控制項或者是動畫,但卻很少 看到深入剖析U...
  • 一、圖片預覽:一、實現功能:需求要實現佈局中為圓形圖片,圖片背景與圖標分開且合併到一個ImageView。二、具體實現: XML中佈局中定義ImageView,關健設置兩個參數 Android:backgroup(設置背景),Android:src(設置ImageVIew中圖片),圓形圖片製作Dra...
  • 對比度指的是一幅圖像中明暗區域最亮的白和最暗的黑之間不同亮度層級的測量,即指一幅圖像灰度反差的大小。 在GPUImage中通過GPUImageContrastFilter來實現 片段著色器 varying highp vec2 textureCoordinate; uniform samp...
  • 這兩天好好的研究了下推送這功能,關於它我將分成兩部分來講,一、IOS手機端,二、Servlet服務端,今天先講下IOS端一、感受下麵講下我對推送這個功能在IOS下的感受,這個算是我做了服務端的功能和手機端的功能後的一個體會吧, 這功能在IOS上是多少給我帶來了點雞肋的感覺,首先很多時候收到推送有延時...
  • 剛開始android編程的時候, 關於ImageView.ScaleType網路上好多, 說實話沒看懂. 本文就是為了講清楚這個, 有用的話轉走, 請註明原地址和作者.
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...