轉載:http://jiangzhengjun.javaeye.com/blog/480996
事件
DOM同時支持兩種事件模式:捕獲型事件和冒泡型事件,但是,捕獲型事件先發生。兩種事件流會觸及DOM中的所有對象,從document對象開
始,也在document對象結束(大部分兼容標準的瀏覽會繼續將事件捕獲/冒泡延續至window對象),DOM中的元素都會連續收到兩次事件,一次在
捕獲過程中,另一次在冒泡過程中。DOM事件模型最獨特的性質是,文本節點也觸發事件(在IE中不會)。點擊文本節點事件流應該如下圖:
傳統事件處理函數有兩種分配方式:在JavaScript中或者在HTML中。
在JavaScript中分配事件處理函數:
- var oDiv = document.getElementById( "div1" );
- oDiv.onclick = function () {
- alert("I was clicked" );
- };
注:在這個分配方法,事件處理函數名稱必須小寫,才能正確響應事件。
在HTML中分配事件處理函數:
- < div onclick = 'alert("I was clicked")' > </ div >
<div onclick='alert("I was clicked")'> </div>
說明:用這種方法,事件處理函數的大小寫可任意,所以onclick等同於onClick、OnClick或ONCLICK,但標準的事
件處理函數應該全部用小寫定義。
說明:傳統分配方式有個缺陷就是隻能分配一個處理函數。於是就出現了其它以下分配方式。
IE中特有的attachEvent()事件處理函數分配方 式:
- var fnClick1 = function () {
- alert("Clicked!" );
- };
- var fnClick2 = function () {
- alert("Also clicked!" );
- };
- var oDiv = document.getElementById( "div" );
- oDiv.attachEvent("onclick" , fnClick1); //綁定事件處理函數
- oDiv.attachEvent("onclick" , fnClick2);
- //do something ...
- oDiv.detachEvent("onclick" , fnClick1); //解除事件處理函數
- oDiv.detachEvent("onclick" , fnClick2);
說明:事件處理函數總是按照添加它們的順序進行調用。
DOM中的事件處理函數綁定
DOM
中方法addEventListener()和removeEventListener()用來分配與移除事件處理函數。與IE不同,需三個參數:事件
名、要分配的處理函數、處理函數是用於冒泡階段還是捕獲階段,如果是捕獲階段,第三個參數爲true。
- var fnClick1 = function () {
- alert("Clicked!" );
- };
- var oDiv = document.getElementById( "div" );
- oDiv.addEventListener("onclick" , fnClick1, false ); //綁定事件處 理函數
- //do something ...
- oDiv.removeEventListener("onclick" , fnClick1, false ); //解除事件處 理函數
說明:也可綁定多個函數,但要注意的是第三個參數刪除時
要與添加時一樣才能真真刪除掉函數
,否則刪除不掉,也不會報錯。
傳統方式oDiv.onclick = fnClick;
與oDiv.addEventListener('onclick',fnClick1,false);
等
價。
事件對象的屬性與方法
鼠標 / 鍵盤屬性
屬性 |
描述 |
IE |
F |
O |
W3C |
altKey |
返回當事件被觸發時, "ALT" 是否被按下。 |
6 |
1 |
9 |
Yes |
button |
返回當事件被觸發時,哪個鼠標按鈕被點擊。 |
6 |
1 |
9 |
Yes |
clientX |
鼠標指針相對於當前窗口的水平座標。 |
6 |
1 |
9 |
Yes |
clientY |
鼠標指針相對於當前窗口的垂直座標。 |
6 |
1 |
9 |
Yes |
ctrlKey |
返回當事件被觸發時, "CTRL" 鍵是否被按 下。 |
6 |
1 |
9 |
Yes |
metaKey |
返回當事件被觸發時, "meta" 鍵是否被按 下。 |
No |
1 |
9 |
Yes |
relatedTarget |
對於 mouseover 事件來 說,該屬性是鼠標指針移到目標節點上時所離開的那個節點。對於 mouseout 事件來 說,該屬性是離開目標時,鼠標指針進入的節點。 |
No |
1 |
9 |
Yes |
screenX |
事件發生時鼠標指針相對於屏幕的水平座標。 |
6 |
1 |
9 |
Yes |
screenY |
鼠標指針相對於屏幕的垂直座標。 |
6 |
1 |
9 |
Yes |
shiftKey |
返回當事件被觸發時, "SHIFT" 鍵是否被按 下。 |
6 |
1 |
9 |
Yes |
IE 屬性
除了上面的鼠標 / 事件屬性, IE 瀏 覽器還支持下面的屬性:
屬性 |
描述 |
cancelBubble |
如果事件句柄想阻止事件傳播到包容對象,必須把該屬性設爲 true 。 |
fromElement |
對於 mouseover 和 mouseout 事 件, fromElement 引用移出鼠標的元素。 |
keyCode |
對於 keypress 事件,該 屬性聲明瞭被敲擊的鍵生成的 Unicode 字符編碼。對於 keydown 和 keyup 事 件,它指定了被敲擊的鍵的虛擬鍵盤代碼。虛擬鍵盤碼可能和使用的鍵盤的佈局相關。 |
offsetX,offsetY |
發生事件的地點在事件源元素的座標系統中的 x 坐 標和 y 座標。 |
returnValue |
如果設置了該屬性,它的值比事件句柄的返回值優先級高。把這個屬性設置爲 fasle , 可以取消發生事件的源元素的默認動作。 |
srcElement |
對於生成事件的 Window 對象、 Document 對 象或 Element 對象的引用。 |
toElement |
對於 mouseover 和 mouseout 事 件,該屬性引用移入鼠標的元素。 |
x,y |
事件發生的位置的 x 座標和 y 坐 標,它們相對於用 CSS 動態定位的最內層包容元素。 |
標準 Event 屬性
下面列出了 2 級 DOM 事 件標準定義的屬性。
屬性 |
描述 |
IE |
F |
O |
W3C |
bubbles |
如果事件是起泡類型,則返回 true ,否則返回 fasle 。 |
No |
1 |
9 |
Yes |
cancelable |
如果用 preventDefault() 方 法可以取消與事件關聯的默認動作,則爲 true ,否則爲 fasle 。 |
No |
1 |
9 |
Yes |
currentTarget |
返回其監聽器觸發事件的節點,即當前處理該事件的元素、文檔或窗口。在捕獲和起泡階 段,該屬性是非常有用的,因爲在這兩個節點,它不同於 target 屬性。 |
No |
1 |
9 |
Yes |
eventPhase |
回事件傳播的當前階段。它的值是 1 、 2 、 3 三 個常量之一,它們分別表示捕獲階段、正常事件派發和起泡階段。 |
|
|
|
Yes |
target |
返回事件的目標節點(觸發該事件的節點),如生成事件的元素、文檔或窗口。 |
No |
1 |
9 |
Yes |
timeStamp |
返回事件生成的日期和時間。 |
No |
1 |
9 |
Yes |
type |
返回發生的事件的類型,即當前 Event 對象表示的事 件的名稱。 它與註冊的事件句柄同名,或者是事件句柄屬性刪除前綴 "on" 比 如 "submit" 、 "load" 或 "click" 。 |
6 |
1 |
9 |
Yes |
標準 Event 方法
下面列出了 2 級 DOM 事 件標準定義的方法。 IE 的事件模型不支持這些方法:
方法 |
描述 |
IE |
F |
O |
W3C |
initEvent() |
初始化新創建的 Event 對象的屬性。 |
No |
1 |
9 |
Yes |
preventDefault() |
通知瀏覽器不要執行與事件關聯的默認動作。 |
No |
1 |
9 |
Yes |
stopPropagation() |
終止事件在傳播過程的捕獲、目標處理或起泡階段進一步傳播。調用該方法後,該節點上處理該事件的處 理程序將被調用,事件不再被分派到其他節點。 |
No |
1 |
9 |
Yes |
事件對象
包含的信息如下:
引
起事件的對象、事件發生時鼠標的信息、事件發生時鍵盤的信息。
事件對象只在發生事件時才被創建,且只有事件處理函數才能訪問。處理完畢就會被銷燬。
IE中,事件對象是window對象的一個屬性event。 採用如下方式進行訪問:
- oDiv.onclick = function () {
- var oEvent = window.event;
- };
DOM標準中,event對象必須作爲唯一參數傳
給事件處理函數,如下訪問:
- oDiv.onclick = function () {
- var oEvent = arguments[0];
- };
當然此種方式可以直接通過參數傳遞進來:
- oDiv.onclick = function (oEvent){ //...}
IE與DOM獲取事件屬性相同的地方:
1、 獲取事件類型(名稱)
- function handleEvent(oEvent) {
- if (oEvent.type == "click" ) {
- alert("clicked" );
- } else {
- if (oEvent.type == "mouseover" ) {
- alert("mouse over" );
- }
- }
- }
- oDiv.onclick = handleEvent;
- oDiv.onmouseover = handleEvent;
2、
獲取按鍵代碼(keydown/keyup事件)
- var iKeyCode = oEvent.keyCode;
3、 檢測是否按下了Shift、Alt、Ctrl鍵
- var bShift = oEvent.shiftKey;
- var bAlt = oEvent.altKey;
- var bCtrl = oEvent.ctrlKey;
4、 獲取客戶端鼠標事件座標
- var iClientX = oEvent.clientX;
- var iClientY = oEvent.clientY;
說明:指與瀏覽器邊界距離。
5、 獲取鼠標距屏幕邊沿座標
- var iScreenX = oEvent.screenX;
- var iScreenY = oEvent.screenY;
IE與DOM獲取事件屬性不同的地方:
1、 獲取目標(事件源)
IE:
- var oTarget = oEvent.srcElement;
DOM:
- var oTarget = oEvent.target;
2、 獲取字符代碼
IE
和DOM都支持event對象的keyCode屬性,它會返回按下的按鍵的數值代碼。但如果按鍵代表一個字符(但非Shift、Ctrl、Alt
等),IE的keyCode將返回字符的代碼(等於它的Unicode值):
- var iCharCode = oEvent.keyCode;
在DOM兼容的瀏覽器中,按鍵代碼與按鍵字符是分開的,要獲取字符代碼,請使用charCode屬性:
- var iCharCode = oEvent.charCode;
如果不確定按下的按鍵是否包含字符,則可使用isChar屬性來進行判斷:
- if (oEvent.isChar){
- var iCharCode = oEvent.charCode;
- }
最後可以用這個值來獲得實際的字符,只要使用String.fromCharCode()方法:
- var sChar = String.fromCharCode(iCharCode);
3、 阻止事件發生
IE:
- oEvent.returnValue = false ;
Mozilla:
- oEvent.preventDefault();
例如:附上使用上下文件菜單
- document.body.oncontextmenu = function (oEvnet) {
- if (isIE) {
- oEvnet = window.event;
- oEvnet.returnValue = false ;
- } else {
- oEvnet.preventDefault();
- }
- };
4、 停止事件冒泡
IE:
- oEvent.cancelBubble = true ;
Mozilla:
- oEvent.stopPropagation();
如下停止事件傳播示例:
- < html onclick = "alert('html')" >
- < head >
- < title > Event Propagation Example </ title >
- < script type = "text/javascript" src = "detect.js" > </ script >
- < script type = "text/javascript" >
- function handleCick(oEvent) {
- alert("input");
- if (isIE) {
- oEvent.cancelBubble = true ;
- } else {
- oEvent.stopPropagation();
- }
- }
- </ script >
- </ head >
- < body onclick = "alert('body')" >
- < input type = 'button' value = 'Click Me' onclick = "handleCick (event)" />
- </ body >
- </ html >
<html onclick="alert('html')">
<head>
<title>Event Propagation Example</title>
<script type="text/javascript" src="detect.js"> </script>
<script type="text/javascript">
function handleCick(oEvent) {
alert("input");
if (isIE) {
oEvent.cancelBubble = true;
} else {
oEvent.stopPropagation();
}
}
</script>
</head>
<body onclick="alert('body')">
<input type='button' value='Click Me' onclick="handleCick (event)" />
</body>
</html>
事件的類型
DOM標準定義了以下幾組事件:
鼠標事件、鍵盤事件、HTML事件(窗口發生變動或者發生特定客戶與服務器交互時觸發)、突變事件(底層DOM結構發生改變時觸發)
鼠標鍵盤事件
要
觸發dblclick事件,在同一個目標上要按順序發生以下事件:
mousedown、mouseup、click、mousedown、mouseup、click、dblclick
mouseout:用戶正要將其移出元素的邊界時發生。
mouseover:移入到某元素上時發生。
mousemove:鼠標
在某個元素移動時發生。
用戶按一次某字符按鍵
時,會按以下發生事件:keydown、keypress、keyup
如果按某非字符鍵
(如Shift),按以下發生事件:keydown、keyup
如果用戶按下一個字符按鍵且不放
,keydown和keypress事件將逐個持續觸發,直
到鬆開。
如果用戶按下一個非字符按鍵且不放
,將只有keydown事件持續觸發。
HTML元素事件
load事件——頁面完全載入後,在window對象上觸發;所有的框架都載入後,在框架上集上觸發; <img/>完全載入後,在其上觸發;或者對於 <object/>元素,當其完全載入後在其上觸發。
unload——頁面完全卸載後,在window對象上觸發;所有的框架都卸載後,在框架上集上觸發;
<img/>完全卸載後,在其上觸發;或者對於 <object/>元素,當其完全卸載後在其上觸發。
abort(異常中斷)事件——用戶停止下載過程時,如果 <object/>對象還未完全載入,就在其上觸發。
error事件——JavaScript腳本出錯時,在window對象上觸發;某個
<img/>的指定圖像無法載入時,在其上觸發;或
<object/>元素無法載入時觸發;或都框架集中的一個或多個框架無法載入時觸發。
select事件——用戶選擇了文本框中的一個或多個字符時觸發( <input/>或者
<textarea/>)。
change事件——文本框( <input/>或者
<textarea/>)失去焦點時並且在它獲取焦點後內容發生過改變時觸發;某個
<select/>元素的值發生改變時觸發。
submit事件——點擊提交按鈕( <input type="submit"/>)時,在
<form/>上觸發。
reset事件——點擊重置按鈕( <input type="reset"/>)時,在
<form/>上觸發。
resize事件——窗口或者框架的大小發生改變時觸發。
scrool事件——用戶在任何帶滾動條的元素上滾動它時觸發。
focus事件——任何元素或者窗口本身獲取焦點時觸發。
blur事件——任何元素或者窗口本身失去焦點時觸發。
load、unload事件
對於window對象可用
兩種方法定義onload事件處理函數:
第一種:window.onload=function(){//...}
第二種: <body
onload='alert()'/>
這兩種是相同的,因爲在HTML中沒有window標籤,所以就加在
<body/>元素上了。
注:不要使用document.body.onload=function(){//...},如果把腳本放在
<head/>標籤中,運行還會出錯,顯示document.body未定義,所以最後用window.onload
在窗口關閉到下一個頁面獲取控制之前,只有很短的時間來執行事件處理函數的代碼,所以最好避免使用onunload事件處理函數。
跨平臺的事件腳本
- /*
- * fileName:eventutil.js
- */
- var EventUtil = new Object;
- //添加事件處理函數
- EventUtil.addEventHandler = function (oTarget, sEventType, fnHandler) {
- if (oTarget.addEventListener) { //如果是支持DOM兼容瀏覽器
- //false 表示在冒泡階段捕獲
- oTarget.addEventListener(sEventType, fnHandler, false );
- } else {
- if (oTarget.attachEvent) { //如果是IE
- oTarget.attachEvent("on" + sEventType, fnHandler);
- } else { //其他瀏覽器
- oTarget["on" + sEventType] = fnHandler;
- }
- }
- };
- //刪除事件處理函數
- EventUtil.removeEventHandler = function (oTarget, sEventType, fnHandler) {
- if (oTarget.removeEventListener) {
- oTarget.removeEventListener(sEventType, fnHandler, false );
- } else {
- if (oTarget.detachEvent) {
- oTarget.detachEvent("on" + sEventType, fnHandler);
- } else {
- oTarget["on" + sEventType] = null ;
- }
- }
- };
- //格式化event對象:把IE的event對象適配成DOM類似的事件對象。注:該方法不單獨使用,僅供後面的 getEvent()方法使用
- EventUtil.formatEvent = function (oEvent) {
- if (isIE && isWin) {
- //由於IE所按的字符的編碼是包含在keyCode屬性中,所以如果事件類型是keypress,
- //需要創建charCode屬性,值等於keyCode,否則爲其他類型事件時設置成0
- oEvent.charCode = (oEvent.type == "keypress" ) ? oEvent.keyCode : 0;
- oEvent.eventPhase = 2;//這個屬性始終等於2代表冒泡階段,因爲IE公支持這個階段
- oEvent.isChar = (oEvent.charCode > 0);//當charCode不爲0時爲true
- oEvent.pageX = oEvent.clientX + document.body.scrollLeft;//鼠標距頁面邊的距離
- oEvent.pageY = oEvent.clientY + document.body.scrollTop;
- oEvent.preventDefault = function () { // 阻止事件適配 IE->DOM
- this .returnValue = false ;
- };
- //relatedTarget爲DOM事件中的第二個事件目標
- if (oEvent.type == "mouseout" ) {
- //鼠標移出時爲toElement(移向的那個對象)
- oEvent.relatedTarget = oEvent.toElement;
- } else {
- if (oEvent.type == "mouseover" ) {
- //鼠標移進時爲fromElement(從哪個對象移進來的)
- oEvent.relatedTarget = oEvent.fromElement;
- }
- }
- //阻止事件冒泡
- oEvent.stopPropagation = function () {
- this .cancelBubble = true ;
- };
- //事件源適配
- oEvent.target = oEvent.srcElement;
- oEvent.time = (new Date).getTime();
- }
- return oEvent;
- };
- //該函數在事件處理函數中使用
- EventUtil.getEvent = function () {
- if (window.event) {
- return this .formatEvent(window.event);
- } else {
- /*函數是一個對象,event對象是一個函數,每個函數都有一個caller屬性,它包含了指向調用它的方法
- 的引用。如,funcA()調用funcB(),那麼funcB.caller就等於funcA。假設某 個事件處理函數調用了
- EventUtil.getEvent(), 那麼EventUtil.getEvent.caller就指向這個事件處理函數的本身。
- 又函數有arguments屬性,而event對象總是事件處理函數的第一個參數*/
- return EventUtil.getEvent.caller.arguments[0];
- }
- };
- < html >
- < head >
- < title > Mouse Events Example </ title >
- < script type = "text/javascript" src = "detect.js" > </ script >
- < script type = "text/javascript" src = "eventutil.js" > </ script >
- < script type = "text/javascript" >
- EventUtil.addEventHandler(window, "load", function () {
- var oDiv = document .getElementById("div1");
- EventUtil.addEventHandler(oDiv, "mouseover", handleEvent);
- EventUtil.addEventHandler(oDiv, "mouseout", handleEvent);
- EventUtil.addEventHandler(oDiv, "mousedown", handleEvent);
- EventUtil.addEventHandler(oDiv, "mouseup", handleEvent);
- EventUtil.addEventHandler(oDiv, "click", handleEvent);
- EventUtil.addEventHandler(oDiv, "dblclick", handleEvent);
- });
- function handleEvent() {
- var oEvent = EventUtil .getEvent();//通過EventUtil的 getEvent()方法獲取IE中適配後的事件對象
- var oTextbox = document .getElementById("txt1");
- oTextbox.value += "/n> " + oEvent.type;
- //oEvent.target 其實是IE屬性裏的srcElement屬性
- oTextbox.value += "/n target is " + oEvent.target.tagName;
- if (oEvent.relatedTarget) {
- //IE 事件對象中本沒有relatedTarget屬性,是由fromElement或toElement適配而來
- oTextbox.value += "/n relatedTarget is " + oEvent.relatedTarget.tagName;
- }
- }
- </ script >
- </ head >
- < body >
- < p >
- Use your mouse to click and double click the red square.
- </ p >
- < div style = "width: 100px; height: 100px; background-color: red"
- id = "div1" > </ div >
- < p >
- < textarea id = "txt1" rows = "15" cols = "50" > </ textarea >
- </ p >
- </ body >
- </ html >
<html>
<head>
<title>Mouse Events Example</title>
<script type="text/javascript" src="detect.js"></script>
<script type="text/javascript" src="eventutil.js"></script>
<script type="text/javascript">
EventUtil.addEventHandler(window, "load", function () {
var oDiv = document.getElementById("div1");
EventUtil.addEventHandler(oDiv, "mouseover", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseout", handleEvent);
EventUtil.addEventHandler(oDiv, "mousedown", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseup", handleEvent);
EventUtil.addEventHandler(oDiv, "click", handleEvent);
EventUtil.addEventHandler(oDiv, "dblclick", handleEvent);
});
function handleEvent() {
var oEvent = EventUtil.getEvent();//通過EventUtil的getEvent()方法獲取IE中適配後的事件對象
var oTextbox = document.getElementById("txt1");
oTextbox.value += "/n>" + oEvent.type;
//oEvent.target其實是IE屬性裏的srcElement屬性
oTextbox.value += "/n target is " + oEvent.target.tagName;
if (oEvent.relatedTarget) {
//IE事件對象中本沒有relatedTarget屬性,是由fromElement或toElement適配而來
oTextbox.value += "/n relatedTarget is " + oEvent.relatedTarget.tagName;
}
}
</script>
</head>
<body>
<p>
Use your mouse to click and double click the red square.
</p>
<div style="width: 100px; height: 100px; background-color: red"
id="div1"></div>
<p>
<textarea id="txt1" rows="15" cols="50"></textarea>
</p>
</body>
</html>