javascript 的 事件類型(事件)


事件通常與函數配合使用,這樣就可以通過發生的事件來驅動函數執行。

事件是文檔或者瀏覽器窗口中發生的,特定的交互瞬間。

事件是用戶或瀏覽器自身執行的某種動作,如click,load和mouseover都是事件的名字。

事件是javaScript和DOM之間交互的橋梁。

你若觸發,我便執行——事件發生,調用它的處理函數執行相應的JavaScript代碼給出響應。

典型的例子有:頁面加載完畢觸發load事件;用戶單擊元素,觸發click事件。

事件流描述的是從頁面中接收事件的順序。

事件發生時會在元素節點與根節點之間按照特定的順序傳播,路徑所經過的所有節點都會收到該事件,這個傳播過程即DOM事件流。

事件傳播的順序對應瀏覽器的兩種事件流模型:捕獲型事件流和冒泡型事件流。

冒泡型事件流事件的傳播是從最特定事件目標到最不特定的事件目標。即從DOM樹的葉子到根。【推薦】

捕獲型事件流事件的傳播是從最不特定事件目標到最特定的事件目標。即從DOM樹的根到葉子。

事件捕獲的思想就是不太具體的節點應該更早接收到事件,而最具體的節點最后接收到事件。

<html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="myDiv">Click me!</div> </body> </html>

上面這段html代碼中,單擊了頁面中的<div>元素,

在冒泡型事件流中click事件傳播順序為<div>—》<body>—》<html>—》document

在捕獲型事件流中click事件傳播順序為document—》<html>—》<body>—》<div>

 

note:

1)、所有現代瀏覽器都支持事件冒泡,但在具體實現中略有差別:

IE5.5及更早版本中事件冒泡會跳過<html>元素(從body直接跳到document)。

IE9、Firefox、Chrome、和Safari則將事件一直冒泡到window對象。

2)、IE9、Firefox、Chrome、Opera、和Safari都支持事件捕獲。盡管DOM標准要求事件應該從document對象開始傳播,但這些瀏覽器都是從window對象開始捕獲事件的。

3)、由於老版本瀏覽器不支持,很少有人使用事件捕獲。建議使用事件冒泡

 

 

DOM標准采用捕獲+冒泡。兩種事件流都會觸發DOM的所有對象,從document對象開始,也在document對象結束。

 

 

DOM標准規定事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。

 

  • 事件捕獲階段:實際目標(<div>)在捕獲階段不會接收事件。也就是在捕獲階段,事件從document到<html>再到<body>就停止了。上圖中為1~3.
  • 處於目標階段:事件在<div>上發生並處理。但是事件處理會被看成是冒泡階段的一部分
  • 冒泡階段:事件又傳播回文檔。

 

note:

 

1)、盡管“DOM2級事件”標准規范明確規定事件捕獲階段不會涉及事件目標,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都會在捕獲階段觸發事件對象上的事件。結果,就是有兩次機會在目標對象上面操作事件。

 

2)、並非所有的事件都會經過冒泡階段 。所有的事件都要經過捕獲階段和處於目標階段,但是有些事件會跳過冒泡階段:如,獲得輸入焦點的focus事件和失去輸入焦點的blur事件。

 

更多詳情見:http://www.cnblogs.com/starof/p/4066381.html

JavaScript中常用的事件

1.onclick事件 點擊事件(onclick並不是js中的方法,onclick只是瀏覽器提供js的一個dom接口,讓js可以操作dom,所以onclick大小寫都是沒問題的,比如HTML代碼就不用區分大小寫) 例: <%@pagelanguage="Java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript"> functionmyFunction(){ alert("測試onclick點擊事件"); } </script> </head> <body> <center> <buttononclick="myFunction()">點擊這里</button> </center> </body> </html> onclick通常在下列基本對象中產生: button(按鈕對象)、checkbox(復選框)、radio(單選框)、reset buttons(重置按鈕)、submit buttons(提交按鈕) 2.onload事件 可以body執行,<bodyonload="alert(123)"></body>,其中onload后面可以寫一個方法,如:onload="test()",然后在JavaScript中寫一個test()方法,則在頁面一開始加載的時候會先調用這個方法 <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript"> functiontest(){ alert("測試onload方法"); } </script> </head> <bodyonload="test()"> </body> </html> 注意:此方法只能寫在<body>標簽之中 3.onchange事件 事件在內容改變的時候觸發,和jQuery中的change()方法一樣 當內容改變時觸發。可用於文本框、列表框等對象,該事件一般用於響應用戶修改內容帶來的其他改變操作。 說明:當用戶向一個文本框中輸入文本時,不會觸發onchange事件,只有用戶輸入結束后,單擊文本框以外的區域,使文本框失去焦點時才觸發該事件,如果是下拉框,則選擇結束后即觸發。 <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript">    functionupperCase(){      varx = document.getElementById("fname").value;      document.getElementById("fname").value = x.toUpperCase();     }    </script> </head> <body>  <p>  <labelfor="name">用戶名:</label>  <inputtype="text"id="fname"onchange="upperCase()"value=""/> </p> </body> </html> 說明:上例實際效果是,當輸入框失去焦點時內容轉成大寫。出現這種情況是由於input必須是失去焦點才會檢測到內容發生改變。而change事件通常是用於下拉菜單select標簽。 4.onblur事件和onfocus事件 當前元素失去焦點時觸發該事件,對應的是onfocus事件:得到焦點事件 <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript">   functionchkvalue(txt) {   if(txt.value=="") alert("文本框里必須填寫內容!");   }  functionsetStyle(x){   document.getElementById(x).style.background="yellow"  }  </script> </head> <body> 失去焦點:  <inputtype="text"name="name"value=""size="30"onblur="chkvalue(this)"><br> 得到焦點: &nbsp;&nbsp;&nbsp;&nbsp;<inputtype="text"id="name"value=""size="30"onfocus="setStyle(this.id)"> </body> </html> 5.onscroll事件 窗口滾動事件:當頁面滾動時調用函數。此事件寫在方法的外面,且函數名后面不加括號,例如window.onscroll=move 例: <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript">   functionmove() {   alert("頁面滾動時調用");   }   window.onscroll = move;  </script> </head> <body> 測試onscroll方法<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR> 測試onscroll方法<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR> 測試onscroll方法<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR> 測試onscroll方法<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR> </body> </html> 6.onsubmit事件 屬於<form>表單元素,寫在<form>表單標簽內。語法:onsubmit=”return 函數名()” 例: <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript">   functionmove() {   alert("測試onsubmit........"+testForm.name.value);   }    </script> </head> <body> <formaction=""method="post"name="testForm"onsubmit="returnmove()"> <inputtype="text"name="name"value=""> <br> <inputtype="submit"name="submit"value="測試onsubmit"/> </form> </body> </html> 2.鼠標相關事件 1.onmousemove和onmouseout和onmouseover事件 Onmouseover:鼠標移動到某對象范圍的上方時,觸發事件調用函數。注意:在同一個區域中,無論怎樣移動都只觸發一次函數。 Onmouseout:鼠標離開某對象范圍時,觸發事件調用函數。 Onmousemove:鼠標移動到某對象范圍的上方時,觸發事件調用函數。注意:在同一個區域中,只要鼠標動一次就觸發一次事件。 例: <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript"> functionbigImg(x) { x.style.height="180px"; x.style.width="180px"; } functionnormalImg(x) { x.style.height="128px"; x.style.width="128px"; } </script> </head> <body> <imgonmousemove="bigImg(this)"onmouseout="normalImg(this)"border="0"src="images/defaultAvatar.gif"alt="Smiley"> </body> </html> 2.onmouseup和onmousedown Onmouseup:當鼠標松開時觸發事件 Onmousedown:當鼠標按下鍵時觸發事件 例: <%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JavaScript的一些常用方法</title> <scripttype="text/javascript"> functionmouseDown(){ document.getElementById("p1").style.color="red"; } functionmouseUp(){ document.getElementById("p1").style.color="green"; } </script> </head> <body> <pid="p1"onmousedown="mouseDown()"onmouseup="mouseUp()"> 請點擊文本!mouseDown()函數當鼠標按鈕在段落上被按下時觸發。此函數把文本顏色設置為紅色。mouseUp() 函數在鼠標按鈕被釋放時觸發。mouseUp() 函數把文本的顏色設置為綠色。 </p> </body> </html>
復制代碼

常用的事件主要有:
    (1)單擊事件:onclick。用戶單擊鼠標按鍵時產生的事件,同時。nclick指定的事件處理程序或代碼將被調用執行.
    (2)改變事件:onchange。當text或textarea元素內的字符值改變或select表格選項狀態改變時發生該事件。
    (3)選中事件:onselect。當text或textarea對象中的文字被選中時會引發該事件。如:
<ipnut type="text" value="默認信息”onselect=alert(”您選中T文本框中的文字”)>
    (4)獲得焦點事件:onfocus。用戶單擊text或textarea以及select對象,即光標落在文本框或選擇框時會產生該事件。如:
    <select name= "zhengjian" onfocus=alert(”我成為焦點”)>
    (5)失去焦點事件:onblur.失去焦點事件正好與獲得焦點事件相對,當text或textarea以及select對象不再擁有焦點而退出后台時,引發該事件。
    (6)載人文件事件:onload,’當頁面文件載人時產生該事件。onload的一個作用就是在首次載人一個頁面文件時檢測cookie的值,並用一個變量為其賦值,使它可以被源代碼使用,本事件是window的事件,但是在HTML中指定事件處理程序時,一般把它寫在<body>標記中。如:
    <body onload=alert(”正在加載頁面,請等待一”)>
    (7)卸載文件事件:onunload。與載人文件事件。nload正好相反,當Web頁面退出時引發的事件,並可更新。ookie的狀態。如:
    <body onunload=confirm(”你確定要離開本頁?”)>
    (8)鼠標鎮蓋事件:onmouseover, onmouseover是當鼠標位於元素上方時所引發的事件。如:
    <input type= "boutton" value=”按鈕”onmouseover= "window. status=‘請您注意下面的狀態欄·;return true">
    (9)鼠標離開事件:onmouseout, onmouseout是當鼠標離開元素時引發的事件。如果和鼠標覆蓋事件同時使用,可以創建動態按鈕的效果。
    (10)一般事件。
   ondbclick:鼠標雙擊事件。
   onkeypress:當鍵盤上的某個鍵被按下並且釋放時觸發的事件,要求頁面內必須有激活的對象。
    onkeydown:當鍵盤上某個鍵被按下時觸發的事件,要求頁面內必須有激活的對象。
    onkeyup:當鍵盤上某個鍵被放開時觸發的事件,要求頁面內必須有激活的對象。
    (11)頁面相關事件。
    onabort:圖片在下載時被用戶中斷時觸發的事件。
    onbeforeunload:當前頁面的內容將要被改變時觸發的事件。

 

DOM事件流

  • “DOM2級事件”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。首先發生的是事件捕獲,為截獲事件提供了機會。然后是實際的目標接收到事件。最后一個階段是冒泡階段。(事件處理中“處於目標階段”被看成冒泡階段的一部分)。
  • IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都會在捕獲階段觸發事件對象上的事件,就是有兩個機會在目標對象上面操作事件。(盡管DOM2級事件規范明確要求捕獲階段不涉及事件目標)。

事件處理程序

HTML 事件處理程序

簡單來講,HTML 事件處理程序是直接在HTML中綁定事件,如下

<input type="button" value="Click Me" onclick="alert(&quot;Clicked&quot;)" />

注意事項:

  • 不能在其中使用未經轉義的HTML語法字符,如&“”<>,因為這是在HTML中綁定的,會造成瀏覽器解析DOM結構錯誤。
  • 擴展函數作用域,來看下面的代碼:

    <!-- 輸出 "Click Me、lzh" --> <form method="post"> <input type="text" name="username" value="lzh"> <input type="button" value="Click Me" onclick="alert(value);alert(username.value);"> </form>

    如果當前元素是一個表單輸入元素,瀏覽器內部大概是這樣實現的:

    function () { with (document) { with (this.form) { with (this) { //元素屬性值 } } } }
    如果沒有form元素,調用username會報錯,所以不論是服務端渲染還是Ajax請求回來數據再渲染,最好還是把form結構寫完整。
    擴展作用域有三個缺點:
  1. 函數被調用時還沒定義會報錯,只好try{}catch(ex){},分離的寫法可以在DOMContentLoaded之后再綁定。
  2. 擴展的作用域鏈在不同瀏覽器中會導致不同的結果。
  3. HTML 與 JavaScript 代碼緊密耦合,如果要更換事件處理程序,需要改動 HTML 代碼和 JavaScript代碼。

DOM0級事件處理程序

  • 每個元素(包括window 和document)都有自己的事件處理程序屬性,這些屬性通常全部小寫。使用 DOM0 級指定的事件處理程序被認為是元素的方法。this 引用當前元素。通過 this 可以訪問元素的任何屬性和方法。DOM0 級事件處理程序在冒泡階段被處理。
var btn = document.getElementById("myBtn"); btn.onclick = function () { alert(this.id); //"myBtn" };

DOM2級事件處理程序

  • addEventListener() 包含三個參數,要處理的事件名、事件處理函數、布爾值,布爾值為true,表示在捕獲階段調用事件處理程序,反之在冒泡階段調用。
  • DOM2 級事件處理程序中的 this 也指向 addEventListener 的那個元素。
  • 可以添加多個事件處理程序,按添加順序依次調用。
  • removeEventListener 無法移除匿名函數的事件處理程序。
var btn = document.getElementById("myBtn"); var handler = function () { alert(this.id); }; btn.addEventListener("click", handler, false); //這里省略了其他代碼 btn.removeEventListener("click", handler, false); // 有效!
  • IE9、Firefox、Safari、Chrome 和Opera 支持DOM2 級事件處理程序。

IE事件處理程序

  • attachEvent detachEvent 接收兩個參數,事件處理程序名稱、事件處理程序函數。由於IE8及更早版本只支持事件冒泡,所以該事件處理程序只支持事件冒泡。
  • 老版本的Opera支持這種方法,但現在Opera已經改用blink內核,IE11已經不支持這種方法,注意 IE9 就已經支持 DOM2 級事件處理程序了。
  • 特別要注意:第一個參數包含on,比如onclick。
  • 區別於DOM0 級事件處理程序,this 指向 'window'。
  • 也可以添加多個事件處理程序。

跨瀏覽器的事件處理程序

var EventUtil = { addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type, handler, false); } else if (element.attachEvent){ element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, removeHandler: function(element, type, handler){ if (element.removeEventListener){ element.removeEventListener(type, handler, false); } else if (element.detachEvent){ element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } };
  • 存在問題:
  1. IE事件處理程序 中的 this 指向 window
  2. 只支持 DOM0 級的瀏覽器不能多次添加事件處理程序,不過這種瀏覽器應該不多了,即使是IE8 也支持attachEvent。
  3. 會不會有一些事件,在瀏覽器支持 DOM2 級事件處理程序的情況下,那些事件只能用 on + name 的形式呢? 之前一直懷疑 (1).xhr.onreadystatechange() 和 (2).DOMNodeInserted 事件,這里我多慮了,經過驗證,(1).是支持 DOM2 級事件的,(2).天生就是 DOM2 級的。這里只是為了打消我的疑慮,記錄下來。

事件對象

DOM 中的事件對象

  • 兼容 DOM 的瀏覽器會將一個 event 對象傳入事件處理程序, IE9 及更高版本可以。無論指定事件處理程序時使用什么方法(DOM0 級 DOM2 級),HTML 事件處理程序可以通過訪問 event 變量得到 event 對象。
  • event 中的屬性和方法都是只讀的
  • 常用屬性:
  1. target 事件的目標
  2. currentTarget 綁定事件的元素,與 'this' 的指向相同
  3. stopPropagation() 取消事件的進一步捕獲或冒泡。如果bubbles為true,則可以使用這個方法
  4. stopImmediatePropagation() 取消事件的進一步捕獲或冒泡,同時阻止任何事件處理程序被調用(DOM3級事件中新增)
  5. preventDefault() 取消事件的默認行為,比如點擊鏈接跳轉。如果 cancelable 是 true,則可以使用這個方法
  6. type 被觸發的事件類型
  7. eventPhase 調用事件處理程序的階段:1表示捕獲階段,2表示“處於目標”,3表示冒泡階段
  • this target currentTarget 舉例:
document.body.onclick = function(event){ alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(event.target === document.getElementById("myBtn")); //true };
  • 通過 event.type 與 switch case 組合,可以通過一個函數處理多個事件。
  • 只有在事件處理程序執行期間,event 對象才會存在;一旦事件處理程序執行完成,event 對象就會被銷毀。

IE 中的事件對象

  • DOM0 級的事件處理程序,event 作為 window 的一個屬性存在。(從 IE9 開始,event 可以從參數中獲得)
  • attachEvent 添加的事件處理程序,event 作為參數傳入,也可以通過 window 來訪問 event 對象。
  • HTML 事件處理程序依然可以通過訪問 event 變量得到 event 對象。
  • 屬性和方法:
  1. cancelBubble 設置 true or false 可以取消事件冒泡
  2. returnValue 設置 true or false 可以取消事件的默認行為。
  3. srcElement 事件的目標(與DOM中的 target 相同)
  • 注意事項:
  1. attachEvent 中的 event.srcElement === this 嗎? 答案是否定的,因為前面說到過 attachEvent 中 this 指向 window, DOM0 級、DOM2 級 事件處理程序 this 才指向 event.target / window.event.srcElement

跨瀏覽器的事件對象

var EventUtil = { getEvent: function(event){ return event ? event : window.event; // window.event DOM0級時IE }, getTarget: function(event){ return event.target || event.srcElement; // event.srcElement for IE }, preventDefault: function(event){ if (event.preventDefault){ event.preventDefault(); } else { event.returnValue = false; // IE } }, stopPropagation: function(event){ if (event.stopPropagation){ event.stopPropagation(); } else { event.cancelBubble = true; // IE } } };

事件類型

  • DOM3 級事件規定了幾類事件;HTML5 也定義了一組事件;還有一些事件沒有規范,瀏覽器的實現不一致。
  • DOM3 級事件模塊在 DOM2 級事件模塊基礎上重新定義了這些事件,也添加了一些新事件。包括 IE9 在內的所有主流瀏覽器都支持 DOM2 級事件。IE9 也支持 DOM3 級事件。

這里只總結一些常見的事件類型

UI事件類型

  • load 事件,當頁面完全加載后(包括所有圖像、JavaScript 文件、CSS 文件等外部資源),就會觸發 window 上面的 load 事件。
EventUtil.addHandler(window, "load", function(){ var image = document.createElement("img"); EventUtil.addHandler(image, "load", function(event){ event = EventUtil.getEvent(event); alert(EventUtil.getTarget(event).src); }); document.body.appendChild(image); image.src = "smile.gif"; //在此之前要先指定事件處理程序 });
  1. script 元素也會觸發 load 事件,據此可以判斷動態加載的 JavaScript 文件是否加載完畢。與圖像不同,只有在設置了 script 元素的 src 屬性並將該元素添加到文檔后,才會開始下載 JavaScript 文件
  2. IE8 及更早版本不支持 script 元素上的 load 事件。
  3. 在不屬於 DOM 文檔的圖像(包括未添加到文檔的 img 元素和 Image 對象)上觸發 load 事件時,IE8 及之前版本不會生成 event 對象。IE9 修復了這個問題。
  • resize 事件
  1. 瀏覽器窗口大小發生變化時會觸發該事件,這個事件在 window 上觸發,IE、Safari、Chrome 和 Opera 會在瀏覽器窗口變化了 1 像素時就觸發 resize 事件,然后隨着變化不斷重復觸發。Firefox 則只會在用戶停止調整窗口大小時才會觸發。
  2. 注意不要在這個事件的處理程序中加入大計算量的代碼,或者采用函數節流的方式優化性能。
  3. 瀏覽器窗口最小化或最大化時也會觸發 resize 事件。
  • scroll 事件
  1. 該事件在 window 上發生,此處和書上講的有點不一樣,webkit 內核或 blink 內核的瀏覽器(Chrome、Opera、Safari)可以通過 document.body.scrollTop 獲取頁面被卷去的高度,而 Trident、Gecko (IE、火狐)可以通過 document.documentElement.scrollTop來獲取該值。
  2. 另外標准模式、混雜模式這兩種方法還有出入,此處不討論。
  3. 所以最好通過 document.body.scrollTop + document.documentElement.scrollTop 的方式獲取 scrollTop 的值,因為兩者之一會等於0,或者使用 document.body.scrollTop || document.documentElement.scrollTop,兩者效果一致。

焦點事件

  1. 這里忽略 DOMFocusIn、DOMFocusOut,因為只有 Opera 支持這個事件,且 DOM3 級事件廢棄了它們。
  2. blur:在元素失去焦點時觸發。這個事件不會冒泡;所有瀏覽器都支持它。
  3. focus:在元素獲得焦點時觸發。這個事件不會冒泡;所有瀏覽器都支持它。
  4. focusin:與 focus 等價,但它冒泡。
  5. focusout:與 blur 等價,也冒泡。
  6. 支持 focusin、focusout 的瀏覽器有:IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。但只支持 DOM2 級事件處理程序
  7. Firefox 不支持 focusin、focusout
  8. blur、focusout 的事件目標是失去焦點的元素;focus、focusin 的事件目標是獲得焦點的元素

鼠標與滾輪事件

  • click 在用戶單擊住鼠標按鈕或按下回車鍵時觸發。 觸發順序 mousedown mouseup click,如果 mousedown、mouseup 其中之一被取消,就不會觸發 click 事件。
  • dblclick 觸發順序 mousedown mouseup click mousedown mouseup click dblclick, 如果中間有事件被取消,dblclick 也不會被觸發
  • mousedown 用戶按下了任意鼠標按鈕時觸發。
  • mouseup 用戶釋放按鈕時觸發
  • mouseenter 在鼠標光標從元素外部首次移動到元素范圍之內時觸發。不冒泡,而且在光標移動到后代元素上不會觸發。DOM2 級事件並沒有定義這個事,但 DOM3 級事件將它納入了規范。IE、Firefox9+和Opera支持這個事件。
  • mouseleave 在位於元素上方的鼠標光標移動到元素范圍之外時觸發。不冒泡,而且在光標移動到后代元素上不會觸發。DOM2 級事件並沒有定義這個事,但 DOM3 級事件將它納入了規范。IE、Firefox9+ 和 Opera 支持這個事件。
  • mouseover 在鼠標指針位於一個元素外部,然后用戶將其首次移入另一個元素邊界之內時觸發。不能通過鍵盤觸發這個事件。
  • mouseout 在鼠標指針位於一個元素上方,然后用戶將其移入另一個元素時觸發。又移入的另一個元素可能位於前一個元素的外部,也可能是這個元素的子元素。不能通過鍵盤觸發這個事件。
  • 用代碼說明一下 mouseenter、mouseleave 和 mouseover、mouseout 的區別:
<!DOCTYPE html> <html lang="zh-cn"> <head> <title>test1</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="test1.css"> </head> <body> <div class="mouseover"> <div class="sub-mouseover"> </div> </div> <div class="mouseenter"> <div class="sub-mouseenter"> </div> </div> <script src="test1.js"></script> </body> </html>
.wrap { width: 200px; height: 100px; } .mouseover { background: pink; } .mouseenter { margin-top: 30px; background: gray; } .sub-mouseover, .sub-mouseenter { width: 100px; height: 50px; background: #AE81FF; }
var div1 = document.querySelector(".mouseover"), div2 = document.querySelector(".mouseenter"); div1.addEventListener("mouseover", function(){ console.log("div1 mouseover"); }); div1.addEventListener("mouseout", function(){ console.log("div1 mouseout"); }) div2.addEventListener("mouseenter", function(){ console.log("div2 mouseenter"); }) div2.addEventListener("mouseleave", function(){ console.log("div2 mouseleave"); })
  • 效果圖
    mouseenter-mouseover

  • 鼠標由左側從上到下依次經過所有 div 的情況,輸出 div1 mouseover div1 mouseout div1 mouseover div1 mouseout div2 mouseenter div2 mouseleave

  • mousemove 當鼠標指針在元素內部移動時重復地觸發。不能通過鍵盤觸發這個事件。
  • 除了 mouseenter、mousedleave,所有鼠標事件都會冒泡,取消鼠標事件將會影響瀏覽器的默認行為,也會影響其它事件,因為鼠標事件與其它事件是密不可分的。
  • 關於 dblclick IE8 及之前版本中的實現有一個小bug,因此在雙擊事件中,會跳過第二個mousedown 和click事件,其順序如下:mousedown mouseup click mouseup dblclick,但還是會觸發 dblclick 事件
  • 客戶區坐標位置:鼠標事件中的 event 都有 clientX clientY 屬性,表示在視口中客戶區的坐標位置,這些值不包括頁面滾動的距離,因此這個位置並不表示鼠標在頁面上的位置:
    坐標示例
  • 頁面坐標位置:pageX、pageY,這兩個屬性表示鼠標光標在頁面中的位置,在頁面沒有滾動的情況下,pageX 和 pageY 的值與 clientX、clientY 的值相等。IE8 及更早版本不支持事件對象上的頁面坐標,不過使用客戶區坐標和滾動信息可以計算出來。這時候需要用到document.body(混雜模式)或document.documentElement(標准模式)中的scrollLeft 和scrollTop 屬性。計算過程如下所示:
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); var pageX = event.pageX, pageY = event.pageY; if (pageX === undefined){ pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft); } if (pageY === undefined){ pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop); } alert("Page coordinates: " + pageX + "," + pageY); });
  • 屏幕坐標位置:screenX、screenY
  • 修改鍵 用戶按住Shift、Ctrl、Alt、Meta(Windows或Cmd,cmd(mac))時觸發鼠標事件,可以在 event 中獲得修改鍵。
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); var keys = new Array(); if (event.shiftKey){ keys.push("shift"); } if (event.ctrlKey){ keys.push("ctrl"); } if (event.altKey){ keys.push("alt"); } if (event.metaKey){ keys.push("meta"); } alert("Keys: " + keys.join(",")); });
  • IE9、Firefox、Safari、Chrome 和Opera 都支持這4 個鍵。IE8 及之前版本不支持metaKey 屬性。另外,舊版本的 IE 有自己的一套寫法。
  • 相關元素 mouseover mouseout 時的 event.relatedTarget,不做詳細記錄。
  • 鼠標按鈕 mousedown mouseup 是在按下/釋放任意鼠標按鈕時觸發的,所以通過 event.button: 0(左) 1(中) 2(右) 可以判斷按的是哪個鍵,但是IE8 及更低版本的瀏覽器不支持,有兼容寫法,此處不詳細敘述。EventUtil.getButton 有詳細實現。
  • mousewheel event.whellDelta 為正數時,向前滾動(回到頂部、頁面向下滑動),負數則反過來,這個值是120的倍數,Opera低版本中正負相反,火狐中有自己的一套方法,這里不做詳細記錄。
  • 觸摸設備
  • 不支持dblclick 事件。雙擊瀏覽器窗口會放大畫面,而且沒有辦法改變該行為。
  • 輕擊可單擊元素會觸發mousemove 事件。如果此操作會導致內容變化,將不再有其他事件發生;如果屏幕沒有因此變化,那么會依次發生mousedown、mouseup 和click 事件。輕擊不可單擊的元素不會觸發任何事件。可單擊的元素是指那些單擊可產生默認操作的元素(如鏈接),或者那些已經被指定了onclick 事件處理程序的元素。
  • mousemove 事件也會觸發mouseover 和mouseout 事件。
  • 兩個手指放在屏幕上且頁面隨手指移動而滾動時會觸發mousewheel 和scroll 事件。
  • 無障礙性問題
  • 如果需要考慮這個問題,不建議使用 click 之外的鼠標事件。因為這個不能通過鍵盤觸發,不利於屏幕閱讀器訪問。此處不詳細記錄。

鍵盤與文本事件

  • keydown: 當用戶按下鍵盤上的任意鍵時觸發,而且如果按住不放的話,會重復觸發此事件。
  • keypress 當用戶按下鍵盤上的字符鍵時觸發,而且如果按住不放的話,會重復觸發此事件。按下Esc 鍵也會觸發這個事件。Safari 3.1 之前的版本也會在用戶按下非字符鍵時觸發keypress事件。
  • keyup:當用戶釋放鍵盤上的鍵時觸發。
  • 觸發順序:keydownkeypresskeyupkeydownkeypress 都是在文本框發生變化之前被觸發的; keyup 事件則是在文本框已經發生變化之后被觸發的。
  • 如果用戶按下了一個字符鍵不放,就會重復觸發 keydown 和keypress 事件,直到用戶松開該鍵為止。
  • 鍵盤事件也支持修改鍵(ctrl等)
  • keydown、keyup 中的 event 有 keyCode, 與ASCII 碼中對應小寫字母或數字的編碼相同。
  • keypress 中的 event 有 charCode,這個值是按下的那個鍵所代表字符的 ASCII 編碼,用 String.fromCharCode() 可以轉換成實際的字符
  • DOM3 級中,有 key 和 char,其中 key 可以直接得到 "k"、"K"、"Shift" 等, char 屬性在按下字符鍵時行為與 key 相同,在按下非字符鍵時為 null,但是支持還不完整,chrome 總是輸出 undefined。
  • keyIdentifier Chrome 已經不推薦使用
  • 表示按下的按鍵在鍵盤的位置,比如按下左右側的shift鍵,這個值就不同,Chrome 和 Safari 的實現有 bug。
  • textInput: 在文本插入文本框之前會觸發textInput 事件。目的是代替keypress,退格鍵不會觸發textInput,但是會觸發keypress(只要改變文本),只有真正可以編輯的區域才會觸發textInput,但是keypress獲得焦點即可觸發。event.data中包含用戶的輸入,拼音輸入法中輸入過程的拼音不會觸發該事件。
  • inputMethod 代表用戶是怎樣輸入的,比如通過粘貼的方式,但是支持的瀏覽器很少。

變動事件

DOM2 級的變動(mutation)事件能在 DOM 中的某一部分發生變化時給出提示,比如 DOM 節點的插入、移除、特性被修改等等

HTML5 事件

  1. contextmenu 事件
EventUtil.addHandler(window, "load", function(event){ var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "contextmenu", function(event){ event = EventUtil.getEvent(event); EventUtil.preventDefault(event); var menu = document.getElementById("myMenu"); menu.style.left = event.clientX + "px"; menu.style.top = event.clientY + "px"; menu.style.visibility = "visible"; }); EventUtil.addHandler(document, "click", function(event){ document.getElementById("myMenu").style.visibility = "hidden"; }); });
  1. beforeunload 事件,用戶關閉標簽頁時提示
EventUtil.addHandler(window, "beforeunload", function(event){ event = EventUtil.getEvent(event); var message = "I'm really going to miss you if you go."; event.returnValue = message; return message; });
  1. DOMContentLoaded 在形成完整DOM樹之后就會觸發,不理會圖像、JavaScript 文件、CSS 文件或其它資源是否已經下載完畢。其實更應該使用 DOMContentLoaded 而不是 window.onload:
EventUtil.addHandler(window, "DOMContentLoaded", function(event){ alert("Content loaded."); }); EventUtil.addHandler(window, "load", function(event){ alert("Window loaded."); });
  • IE9+、Firefox、Chrome、Safari 3.1+ 和 Opera9+ 都支持 DOMContentLoaded 事件。
  1. readystatechange 事件,略。
  2. pageshow 和 pagehide 事件,此處要了解 Firefox 和 Opera 有一個特性叫 “往返緩存”(back-forward cache/bfcache),用戶點擊“前進”、“后退”按鈕時,會將頁面緩存在內存。不重新加載,JavaScript的狀態會保留。但是無論頁面是否來自 bfcache,都會觸發 pageshow 事件,pageshow 的事件處理程序的 event 對象中有 event.persisted 屬性,為 true 代表頁面來自bfcache,同樣 pagehide 事件觸發時,如果頁面被保存到 bfcache 中,則該屬性為 true。支持pageshow、pagehide 事件的瀏覽器有 Firefox、Safari5+、Chrome 和 Opera。 IE9 及以前的版本不支持這兩個事件。指定了 onunload 事件處理程序的頁面會被自動排除在 bfcache 之外。
  3. hashchange 事件。在 window 上觸發,event 包含 oldURL、newURL 兩個屬性。支持該事件的有 IE8+、Firefox3.6+、Safari5+、Chrome 和 Opera10.6+,但oldURL、newURL只有Firefox6+、Chrome和Opera支持。所以最好用 location 來指定當前的 hash:
EventUtil.addHandler(window, "hashchange", function(event){ console.log(location.hash); })

設備事件

  • orientationchange 事件,屏幕轉動。

觸摸與手勢事件

  • touchstart: 當手指觸摸屏幕時觸發;即使已經有一個手指放在了屏幕上也會觸發。
  • touchmove: 當手指在屏幕上滑動時連續地觸發。在這個事件發生期間,調用preventDefault() 可以阻止滾動。
  • touchend:當手指從屏幕上移開時觸發。
  • touchcancel:當系統停止跟蹤觸摸時觸發。關於此事件的確切觸發時間,文檔中沒有明確說明。
  • event 對象中包含的常見 DOM 屬性有:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey。
  • event 對象中還包含以下用於跟蹤觸摸的屬性:
  1. touches:表示當前跟蹤的觸摸操作的Touch 對象的數組。
  2. targetTouchs:特定於事件目標的Touch 對象的數組。
  3. changeTouches:表示自上次觸摸以來發生了什么改變的Touch 對象的數組。每個Touch 對象包含下列屬性:clientX、clientY、pageX、pageY、screenX、screenY、target、identifier(標識觸摸的唯一ID)
function handleTouchEvent(event) { //only for one touch if (event.touches.length == 1) { var output = document.getElementById("output"); switch (event.type) { case "touchstart": output.innerHTML = "Touch started (" + event.touches[0].clientX + "," + event.touches[0].clientY + ")"; break; case "touchend": output.innerHTML += "<br>Touch ended (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")"; break; case "touchmove": event.preventDefault(); //prevent scrolling output.innerHTML += "<br>Touch moved (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")"; break; } } }
  • 一次觸摸的事件觸發順序為:touchstart、mouseover、mousemove(一次)、mousedown、mouseup、click、touchend
  • 手勢事件:
  1. gesturestart:當一個手指已經按在屏幕上而另一個手指又觸摸屏幕時觸發。
  2. gesturechange:當觸摸屏幕的任何一個手指的位置發生變化時觸發。
  3. gestureend:當任何一個手指從屏幕上面移開時觸發。
  • 屬性有標准的鼠標事件屬性,還有兩個:rotation(正值表示順時針)和scale(從1開始)

內存和性能

  • 每個函數都是對象,都會占用內存;內存中的對象越多,性能就越差。
  • 必須事先指定所有事件處理程序而導致的 DOM 訪問次數,會延遲整個頁面的交互就緒時間。

事件委托

<body> <ul id="myLinks"> <li id="goSomewhere">Go somewhere</li> <li id="doSomething">Do something</li> <li id="sayHi">Say hi</li> </ul> <script type="text/javascript"> (function(){ var list = document.getElementById("myLinks"); EventUtil.addHandler(list, "click", function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); switch(target.id){ case "doSomething": document.title = "I changed the document's title"; break; case "goSomewhere": location.href = "http://www.wrox.com"; break; case "sayHi": alert("hi"); break; } }); })(); </script> </body>
  • 上面的方法只取得了一個 DOM 元素,只添加了一個事件處理程序,占用的內存更少。
  • 如果將事件委托到 document 中,會更有優勢:
  1. document 對象很快就可以訪問,而且可以在頁面生命周期的任何時點上為它添加事件處理程序(無需等待 DOMContentLoaded 或 load 事件)。
  2. 在頁面中設置事件處理程序所需的時間少。只添加一個事件處理程序所需的 DOM 引用更少,所花的時間也更少。
  3. 整個頁面占用的內存空間更少,能夠提升整體性能。
  • 最適合采用事件委托技術的事件包塊 clickmousedownmouseupkeydownkeyup 和 keypress

移除事件處理程序

  • 如果你知道某個元素即將被移除,那么最好手工移除事件處理程序,因為有的瀏覽器(尤其是 IE)不會作出恰當地處理,它們很有可能會將對元素和對事件處理程序的引用都保存在內存中。
  • IE8 及更早的版本在頁面被卸載(刷新,切換頁面)之前沒有清理干凈事件處理程序,它們會滯留在內存中,可以通過 onunload 事件處理程序移除所有事件處理程序。

模擬事件

  • 在測試 Web 應用程序,模擬觸發事件是一種極其有用的技術。DOM2 級規范為此規定了模擬特定事件的方式,IE9、Opera、Firefox、Chrome 和 Safari 都支持這種方式。IE有它自己模擬事件的方式(IE8 及以下才要用到)

DOM 中的事件模擬

  • 可以在 document 對象上使用 createEvent 方法創建 event 對象。這個方法接收一個參數,即表示要創建的事件類型的字符串。在 DOM2 級中,所有這些字符串都使用英文復數形式,而在 DOM3 級中變成了單數。這個字符串可以是下列幾個字符串之一:
  1. UIEvents,DOM3 級中是 UIEvent
  2. MouseEvents: 一般化的鼠標事件,DOM3 級中是 MouseEvent
  3. MutationEvents: 一般化的 DOM 變動事件。 ...
  4. HTMLEvents 一般化的 HTML 事件。沒有對應的 DOM3 級事件(HTML 事件被分割到其他類別中)

模擬鼠標事件

  • createEvent 方法返回的 event 對象中,有 initMouseEvent() 方法,需要傳 15 個參數。type(比如"click"),bubbles(Boolean) 是否冒泡,應該設置為 true, cancelable(Boolean) 應該設置為 true,view(幾乎總是document.defaultView), detail(通常設置為0), screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button(表示按下了哪個鼠標,默認0), relatedTarget(只有在模擬 mouseover 或 mouseout時使用)
  • 將 event 對象傳給 DOM 節點的 dispatchEvent 方法即可觸發事件,如下:
<body> <input type="button" value="Click me" id="myBtn" /> <input type="button" value="Send click to the other button" id="myBtn2" /> <p>This example works in DOM-compliant browsers (not IE).</p> <script type="text/javascript"> (function(){ var btn = document.getElementById("myBtn"); var btn2 = document.getElementById("myBtn2"); EventUtil.addHandler(btn, "click", function(event){ alert("Clicked!"); alert(event.screenX); //100 }); EventUtil.addHandler(btn2, "click", function(event){ //create event object var event = document.createEvent("MouseEvents"); //initialize the event object event.initMouseEvent("click", true, true, document.defaultView, 0, 100, 0, 0, 0, false, false, false, false, 0, btn2); //fire the event btn.dispatchEvent(event); }); })(); </script> </body>

模擬鍵盤事件

  • "DOM2 級事件"的草案中本來包含了鍵盤事件,但在定稿前又被刪除了;Firefox 根據其草案實現了鍵盤事件。但跟 "DOM3 級事件"中的鍵盤事件有很大區別。
  • DOM3 級規定,調用 createEvent() 並傳入 "KeyboardEvent" ,返回鍵盤事件,有 initKeyEvent() 方法。這個方法接收一下參數
  • type, bubbles, cancelable, view, key(按下的鍵的鍵碼), location(按下了哪里的鍵,0:主鍵盤,1:左,2:右,3:數字鍵盤,4:虛擬鍵盤,5:手柄), modifiers: 空格分隔的修改鍵列表,如 "Shift", repeat(在一行中按了這個鍵多少次)
    DOM3 級不提倡 keypress 事件, 因此只能模擬 keydown keyup

IE 中的事件模擬

第一步:document.createEventObject()
第二步: 通過賦值的方式初始化事件對象,就是 event.screenX = 0 這些
第三步:btn.fireEvent("onclick", event);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM