【使用 DOM】使用事件

来源:http://www.cnblogs.com/luka/archive/2016/08/17/5773913.html
-Advertisement-
Play Games

1. 使用簡單事件處理器 可以用幾種不同的方式處理事件。最直接的方式是用事件屬性創建一個簡單事件處理器(simple event handler)。元素為它們支持的每一種事件都定義了一個事件屬性。舉個例子,onmouseover事件屬性對應全局事件mouseover,後者會在用戶把游標移動到元素占據 ...


1. 使用簡單事件處理器

可以用幾種不同的方式處理事件。最直接的方式是用事件屬性創建一個簡單事件處理器(simple event handler)。元素為它們支持的每一種事件都定義了一個事件屬性。舉個例子,onmouseover事件屬性對應全局事件mouseover,後者會在用戶把游標移動到元素占據的瀏覽器屏幕的上方時觸發。(這是一種通用的模式:大多數事件都有一個對應的事件屬性,其名稱定義為 on<eventname>)

1.1 實現簡單的內聯事件處理器

使用某個屬性最直接的方式是給它指派一組JavaScript語句。當該事件被觸發後,瀏覽器就會執行提供的語句。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用內聯JavaScript處理事件</title>
    <style>
        p {background: gray;color:white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p onmouseover="this.style.background='white';this.style.color = 'black'">
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p>
</body>
</html>

此例中,指定了兩條JavaScript語句用來想要mouseover事件。具體方式是設置它們作為文檔里p元素onmouseover事件屬性的值。這些語句如下:

this.style.background='white';
this.style.color = 'black';

這些是直接應用到元素style屬性上的CSS屬性。瀏覽器會把特殊變數 this 的值設置為代表觸發事件元素的HTMLElement 對象,而style 屬性會返回該元素的CSSStyleDeclaration 對象。

如果在瀏覽器中載入這個文檔,style元素定義的初始樣式就會被應用到p元素上。當把滑鼠移至元素上方時,JavaScript語句就會被執行。

這種轉變是單向的:當滑鼠離開元素的屏幕區域時樣式不會重置。許多事件是成雙成對的。與mouseover相對的事件被稱為 mouseout,可以通過onmouseout事件屬性來處理這一事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用內聯JavaScript處理事件</title>
    <style>
        p {background: gray;color:white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p onmouseover="this.style.background='white';this.style.color = 'black';"
   onmouseout="this.style.removeProperty('color');this.style.removeProperty('background');">
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p>
</body>
</html>

添加這些代碼後,此元素就能響應滑鼠進入和離開它所占據的屏幕區域了。

1.2 實現一個簡單的事件處理函數

為了在一定程度解決繁瑣和重覆添加問題,可以定義一個函數,並將函數名指定為元素事件屬性的值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用函數來處理事件</title>
    <style>
        p {background: gray;color:white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p onmouseover="handleMouseOver(this)"   onmouseout="handleMouseOut(this)">
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p >
<p onmouseover="handleMouseOver(this)"  onmouseout="handleMouseOut(this)">
    一些年輕人,通過高端消費來營造自己高端收入的形象
</p>
<script>
    function handleMouseOver(elem){
        elem.style.background='white';
        elem.style.color = 'black';
    }
    function handleMouseOut(elem){
        elem.style.removeProperty('color');
        elem.style.removeProperty('background');
    }
</script>
</body>
</html>

此例中,定義了一些JavaScript函數,它們所包含的語句是用來想要滑鼠事件的。並且還在onmouseover和onmouseout屬性里指定了這些函數。特殊值this 指的是觸發事件的元素。

這種方式相對於之前的技巧有了進步。重覆添加工作變得了更少了,代碼也更易閱讀了。但是,希望能讓事件與HTML元素互相分離,要做到這一點,需要在訪問DOM。

 

2. 使用DOM和事件對象

前面例子演示的簡單事件處理器用於基本任務是可行的,但如果想要進行更為複雜的處理(以及更優雅地定義事件處理器),就需要使用DOM和JavaScript的Event對象了。下麵例子展示瞭如何使用Event對象,以及如何用DOM來將某個函數與事件關聯起來。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用DOM構建事件處理</title>
    <style>
        p {background: gray;color:white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p>
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p >
<p>
    一些年輕人,通過高端消費來營造自己高端收入的形象
</p>
<script type="application/javascript">
    var pElems = document.getElementsByTagName("p");
    for(var i=0;i<pElems.length;i++){
        pElems[i].onmousemove = handleMouseOver;
        pElems[i].onmouseout = handleMouseOut;
    }
    function handleMouseOver(e){
        e.target.style.background='white';
        e.target.style.color = 'black';
    }
    function handleMouseOut(e){
        e.target.style.removeProperty('color');
        e.target.style.removeProperty('background');
    }
</script>
</body>
</html>

這段腳本(必須把他移到頁尾,因為操作的是DOM)找到想要處理事件的所有元素,然後給事件處理器屬性設置一個函數名。所有事件都擁有像這樣的屬性。它們的命名方式是一致的:以 on 開頭,後接事件的名稱。

PS:請註意這裡使用函數的名稱來將它註冊成一個事件監聽器。一個常見的錯誤是把括弧加在函數名的後面,使 handleMouse變成handerMouse()。這樣做的後果是函數會在腳本執行時(而不是事件觸發時)被調用。

此例中那些處理事件的函數定義了一個名為e的參數。它會被設成瀏覽器所創建的一個Event對象,用於在事件觸發時代表該事件。這個Event對象提供了所發生的事件信息,能夠更加靈活地(相對於把代碼放在元素屬性中而言)對用戶交互行為作出反應。在此例中,用target屬性來獲取觸發事件的HTMLElement,這樣就能使用樣式屬性來改變它的外觀。

在展示事件對象之前,想演示另一種指定事件處理函數的方式。事件屬性(名稱以on開頭的那些)一般來說是最容易的方式,但也可以使用addEventListener 方法,它由HTMLElement對象實現。還可以使用removeEventListener 方法來取消函數與事件之間的關聯。可以在這兩個方法中都能把事件類型和處理它們的函數表達為參數,如下麵的例子所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用addEventListener和removeEventListener方法</title>
    <style>
        p {background: gray;color:white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p>
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p >
<p id="block2">
    一些年輕人,通過高端消費來營造自己高端收入的形象
</p>
<button id="btn">Press Me</button>
<script type="application/javascript">
    var pElem = document.getElementsByTagName("p");
    for(var i=0;i<pElem.length;i++){
        pElem[i].addEventListener("mouseover",handleMouseOver);
        pElem[i].addEventListener("mouseout",handleMouseOut);
    }
    document.getElementById("btn").onclick = function(){
        document.getElementById("block2").removeEventListener("mouseout",handleMouseOut);
    }
    function handleMouseOver(e){
        e.target.style.background='white';
        e.target.style.color = 'black';
    }
    function handleMouseOut(e){
        e.target.style.removeProperty('color');
        e.target.style.removeProperty('background');
    }
</script>
</body>
</html>

此例中的腳本使用addEventListener方法把handleMouseOver和handleMouseOut函數註冊成p元素的事件處理器。當button被點擊後,腳本用removeEventListener方法取消了id值為block2 的p元素與handleMouseOut函數之間的關聯。

addEventListener 方法的優點在於它讓你能夠訪問某些高級事件特性。下表介紹了Event對象的成員。

 

2.1 按類型區分事件

type 屬性會告訴你正在處理的是哪種類型的事件。這個值以字元串的形式提供,比如 mouseover。有了探測事件類型的能力,就可以用一個函數來處理多個類型了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用type屬性</title>
    <style type="text/css">
        p {background: gray;color: white;padding: 10px;margin: 5px;border: thin solid orange;}
    </style>
</head>
<body>
<p>
    你承受的苦難並不比他人多太多,痛苦主要來自敏感和脆弱。
</p >
<p id="block2">
    一些年輕人,通過高端消費來營造自己高端收入的形象
</p>
<script type="application/javascript">
    var pElems = document.getElementsByTagName("p");
    for(var i=0;i<pElems.length;i++){
        pElems[i].onmouseover = handleMouseEvent;
        pElems[i].onmouseout = handleMouseEvent;
    }
    function handleMouseEvent(e){
        if(e.type == "mouseover"){
            e.target.style.background='white';
            e.target.style.color = 'black';
        }else if(e.type == "mouseout"){
            e.target.style.removeProperty('color');
            e.target.style.removeProperty('background');
        }
    }
</script>
</body>
</html>

此例中,只用了一個handleMouseEvent 這一個事件處理器,通過使用type屬性來判斷正在處理的是哪一種事件。

 

2.2 理解事件流

一個事件的生命周期包括三個階段:捕捉(capture)、目標(target)和冒泡(bubbing)。

(1) 理解捕捉階段

當某個事件被觸發時,瀏覽器會找出事件涉及的元素,它被稱為該事件的目標。瀏覽器會找出body元素和目標之間的所有元素並分別檢查它們,看看它們是否帶有事件處理器且要求獲得其後代元素觸發事件的通知。瀏覽器會先觸發這些事件處理器,然後才會輪到目標自身的處理器。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>捕捉事件</title>
    <style type="text/css">
        p {background: gray;color: white;padding: 10px;margin: 5px;border: thin solid orange;}
        span {background: white;color: black;padding: 2px;cursor: default;}
    </style>
</head>
<body>
<p id="block1">
    你承受的苦難並不比他人多太多,痛苦主要來自<span id="point">敏感和脆弱</span></p >
<script type="application/javascript">
    var point = document.getElementById("point");
    var textBlock = document.getElementById("block1");
    point.addEventListener("mouseover",handleMouseEvent);
    point.addEventListener("mouseout",handleMouseEvent);
    textBlock.addEventListener("mouseover",handleDescendantEvent,true);
    textBlock.addEventListener("mouseout",handleDescendantEvent,true);
    function handleDescendantEvent(e){
        if(e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE){
            e.target.style.border = "thick solid red";
            e.currentTarget.style.border = "thick double blue";
        }else if(e.type == "mouseout" && e.eventPhase == Event.CAPTURING_PHASE){
            e.target.style.removeProperty("border");
            e.currentTarget.style.removeProperty("border");
        }
    }
    function handleMouseEvent(e){
        if(e.type == "mouseover"){
            e.target.style.background='black';
            e.target.style.color = 'white';
        }else if(e.type == "mouseout"){
            e.target.style.removeProperty('background');
            e.target.style.removeProperty('color');
        }
    }
</script>
</body>
</html>

此例中,定義了一個span作為p元素的子元素,然後註冊了mouseover和mouseout事件的處理器。當註冊父元素(即p元素)時,給addEventListener方法添加了第三個參數,就像這樣:

textBlock.addEventListener("mouseover",handleDescendantEvent,true);

這個額外的參數告訴瀏覽器讓p元素在捕捉階段接收後代元素的事件。當mouseover事件被觸發時,瀏覽器會從HTML文檔的跟節點起步,一路沿著DOM向目標(也就是觸發事件的元素)前進。對層級里的每一個元素,瀏覽器都會檢查它是否對捕捉到的事件感興趣。可以從下圖看到示例文檔的順序。

對每一個元素,瀏覽器都會調用它所有啟用捕捉的監聽器。此例中,瀏覽器會找到並調用註冊在p元素上的handleDescendantEvent函數。當handleDescendantEvent函數被調用時,Event對象包含了目標元素的信息(通過target),還有導致函數被調用的元素(通過currentTarget屬性)。這裡同時使用了這兩個屬性,這樣就能修改p元素和其子元素span的樣式了。

 

事件捕捉讓目標元素的各個上級元素都有機會在事件傳遞到目標元素之前對其做出對應。上級元素的事件處理器可以阻止事件流向目標,方法是對Event對象調用stopPropagation或stopImmediatePropagation函數。這兩個函數的區別在於,stopPropagation會確保調用當前元素上註冊的所有事件監聽器,而stopImmediatePropagation會忽略任何未觸發的監聽器。為了展示瞭如何給hanldDescendantEvent事件處理器添加stopPropagation函數,修改上面例子的JavaScript代碼中的hanldDescendantEvent函數如下:

  function handleDescendantEvent(e){
        if(e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE){
            e.target.style.border = "thick solid red";
            e.currentTarget.style.border = "thick double blue";
        }else if(e.type == "mouseout" && e.eventPhase == Event.CAPTURING_PHASE){
            e.target.style.removeProperty("border");
            e.currentTarget.style.removeProperty("border");
        }
        e.stopPropagation();
    }

做了這個改動後,瀏覽器的捕捉階段就會在p元素上的處理器被調用時結束。瀏覽器不會檢查其他任何元素,並且會跳過目標和冒泡階段。對此例來說,這就意味著handleMouseEvent 函數里的樣式變化不會被應用(以響應mouseover事件),如此例修改後的顯示效果如下:

請註意此例在處理器里檢查了事件類型,並用 eventPhase屬性來確定事件所處的階段,就像這樣:

...
 if(e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE){
...

在註冊事件監聽器時啟動捕捉事件並不能停止針對元素自身的事件。此例中,p元素占據了瀏覽器屏幕空間,它同樣會響應mouseover事件。為了避免這一點,進行了檢查,確保只有在處理捕捉階段的事件(只針對後代元素的事件,處理此事件完全是因為註冊了啟用捕捉的監聽器)時才會應用樣式改動。eventPhase屬性會返回下表裡展示的三個值之一。它們代表了事件生命周期的三個階段。

 

 

(2) 理解目標階段

目標階段是三個階段中最簡單的。當捕捉階段完成後,瀏覽器會觸發目標元素上任何已添加的事件類型監聽器,如下圖所示:

這裡要註意的唯一一點是可以多次調用addEventListener函數,因此某個給定事件類型可以有不止一個監聽器。

PS:如果在目標階段調用stopPropagation或stopImmediatePropagation函數,相當於終止了事件流,不再進入冒泡階段。

 

(3) 理解冒泡階段

完成目標階段之後,瀏覽器開始轉而沿著上級元素鏈朝 body元素前進。在沿途的每個元素上,瀏覽器都會檢查是否存在針對該事件類型但沒有啟用捕捉的監聽器(也就是說,addEventListener函數的第三個參數是 false)。這就是所謂的事件冒泡。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
    <style type="text/css">
        p {background: gray;color: white;padding: 10px;margin: 5px;border: th

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

-Advertisement-
Play Games
更多相關文章
  • 回到目錄 關於Lind.DDD.Api的使用與客戶端的調用 作者:張占嶺 花名:倉儲大叔 框架:Lind.DDD,Lind.DDD.Api 目錄 Api里註冊全局校驗特性 1 Api中設置全局的Cors跨域資源訪問 2 Api直接返回Json,而不是Xml 2 Api中Controller的Get, ...
  • 線上實例 ...
  • 測試 ...
  • 頭:header 內容:content/container 尾:footer 導航:nav 側欄:sidebar 欄目:column 頁面外圍控制整體佈局寬度:wrapper 左右中:left right center 登錄條:loginbar 標誌:logo 廣告:banner 頁面主體:main ...
  • 我們來看看CSS重要屬性--float。 以下內容分為如下小節: 1:float屬性 2:float屬性的特性 2.1:float之文字環繞效果 2.2:float之父元素高度塌陷 3:清除浮動的方法 3.1:html法 3.2:css偽元素法 4:float去空格化 5:float元素塊狀化 6: ...
  • 0.解決的問題 a.當選擇器語法沒有問題,找不到元素時,讓jquery報錯 b.選擇器語法有問題,程式無法繼續執行時,讓jquery報錯 主要針對傳遞字元串,嘗試前請備份jquery庫,最好改變名字加已區分. 1.環境配置 jquery-3.0.0.js未壓縮版 2.選擇器語法沒有問題,找不到元素 ...
  • 運行效果如下圖所示: ...
  • transform transition-origin:設置對象中變換所參照的原點 none:無變換 translate(<length>[,<length>]):指定對象的2D translation(2D平移)。第一個參數對應X軸,第二個參數對應Y軸。如果第二個參數未提供,則預設是為0. tra ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...