一步步學習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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...