[toc]
##事件處理程序
在`DOM`中定義了一些事件, 而響應某個事件的函數就叫事件處理程序(或事件偵聽器)。事件處理程序的名字一般以“on”開頭,例如:`onclick`等
##事件冒泡與捕獲
事件流指的是頁面中接收事件的順序,`IE`,火狐和`chrome`瀏覽器都是事件冒泡,所謂是事件冒泡指的是事件最開始由最具體的元素接收,然后逐級向上傳播到不具體的節點。而事件捕獲則正好相反,事件捕獲是由`Netscape`提出的,事件冒泡和捕獲具體如下圖所示:

雖然事件捕獲是Netscape唯一支持的事件流模型,但目前IE9,火狐和谷歌也都支持這種事件流模型。
### 事件冒泡的好處
因為事件具有冒泡機制,因此我們可以利用冒泡的原理,把事件加到父級上,觸發執行效果。這樣做的好處當然就是提高性能了,
```
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function () {
var aUl = document.getElementsById("bubble");
var aLi = aUl.getElementsByTagName("li");
for(var i = 0;i<aLi.length;i++){
aLi[i].onmouseover = function () {
this.style.backgroundColor = "blue";
};
ali[i].onmouseout = function () {
this.style.backgroundColor = "";
}
}
};
</script>
</head>
<body>
<div>
<ul id = "bubble">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</body>
```
這樣我們就可以做到li上面添加鼠標事件。但是如果說我們可能有很多個`li`用`for`循環的話就比較影響性能。
下面我們可以用`事件委托`的方式來實現這樣的效果。`html`不變:
```
<script type="text/javascript">
window.onload = function () {
var aUl = document.getElementsById("bubble");
var aLi = aUl.getElementsByTagName("li");
//不管在哪個事件中,只要你操作的那個元素就是事件源。
// ie:window.event.srcElement
// 標準下:event.target
aUl.onmouseover = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == "li"){
target.style.background = "blue";
}
};
aUl.onmouseout = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() = "li"){
target.style.background = "";
}
}
};
</script>
```
那么,如何阻止事件的冒泡呢,看下面一個例子:
```
<div onclick="showMsg(this,event)" id="outSide" style="width:100px; height:100px; background:#000; padding:50px">
<div onclick="showMsg(this,event)" id="inSide" style="width:100px; height:100px; background:#CCC"></div>
</div>
<script type="text/javascript">
//阻止事件冒泡后,你點擊灰色盒子,整個過程只彈一次對話框了(注意與默認情況對比)
function showMsg(obj,e)
{
alert(obj.id);
stopBubble(e)
}
//阻止事件冒泡函數
function stopBubble(e)
{
if (e && e.stopPropagation)
e.stopPropagation()
else
window.event.cancelBubble=true
}
</script>
```
點擊黑色外圍的效果圖:

##DOM 0級事件處理程序
通過`js`指定事件處理程序通常是將回調函數賦給這個事件處理程序的屬性。每個元素都有自己的事件處理程序屬性(屬性小寫,例如:`onclick`)
```
btn.onclick = function(){
console.log('hello');
};
```
使用DOM 0級指定的事件處理程序被認為是元素的方法。因此,this指向當前元素:
```
var btn = document.getElementById('myDiv');
//DOM上觸發的事件會產生一個事件對象event
btn.onclick = function (event) {
alert(this.id);//myDiv
};
```
##DOM level 1
`DOM level 1` 專注于 `HTML` 和 `XML` 文檔模型。它含有文檔導航和處理功能。
`DOM level 1` 于 1998 年 10 月 1 日成為 W3C 推薦標準。
第二版的工作草案在 2000 年 9 月 29 日。
值得一提的是:`DOM level 0` 并不是 W3C 規范。而僅僅是對在 `Netscape Navigator 3.0` 和 `IE 3.0` 中的等價功能性的一種定義。
##DOM 2級事件處理程序
`DOM 2`級定義了兩個方法,用于指定和刪除事件處理程序的操作:`addEventListener()`和`removeEventListener()`,他們都接受三個參數:
```
1.事件名。比如上面的click
2.作為事件處理程序的函數。
3.布爾值(true表示捕獲階段調用事件處理程序,false表示冒泡階段)
```
通過`Element`對象的`addEventListener`方法,也可以定義事件的回調函數。
```
//element.addEventListener(event, function, useCapture)
var btn = document.getElementById('myDiv');
btn.addEventListener('click', function () {
console.log(this.id);
},false);
```
##IE中的事件處理程序
IE9之前的IE瀏覽器不支持`addEventListener()`和`removeEventListener()`。
與其他瀏覽器不同的是,IE使用的是`attachEvent()`和`detachEvent()`方法來為`DOM`添加事件處理程序,由于`IE8`及更早版本只支持事件冒泡,所以他們只接受兩個參數:
```
1、事件處理程序名稱(前面要加on)
2、事件處理程序函數
```
使用`attachEvent()`添加的事件處理程序如下:
```
var btn = document.getElementById('myDiv');
btn.attachEvent('onclick', function () {
console.log(this.id);
});
```
值得注意的是,使用`attachEvent()`方法的情況下,事件處理程序會在全局作用域中運行,所以,此時`this`等于`window`
##事件對象
在觸發`DOM`上的某個事件時,會產生一個事件對象`event`,這個對象包含著所有與事件相關的信息。包括導致事件的元素、事件的類型以及其他與特定事件相關的信息。`event`對象會被作為第一個`參數`傳遞給事件監聽的回調函數。我們可以通過這個`event`對象來獲取到大量當前事件相關的信息:
```
type (String) — 事件的名稱
target (node) — 事件起源的DOM節點
currentTarget?(node) — 當前回調函數被觸發的DOM節點(后面會做比較詳細的介紹)
bubbles (boolean) — 指明這個事件是否是一個冒泡事件(接下來會做解釋)
preventDefault(function) — 這個方法將阻止瀏覽器中用戶代理對當前事件的相關默認行為被觸發。比如阻止\<a\>元素的click事件加載一個新的頁面 cancelable (boolean) — 這個變量指明這個事件的默認行為是否可以通過調用event.preventDefault來阻止。 stopPropagation (function) — 取消事件的進一步捕獲或冒泡,bubbles為true使用這個方法 eventPhase:返回一個數字,表示事件目前所處的階段,0為事件開始從DOM表層向目標元素傳播,1為捕獲階段,2為事件到達目標元素,3為冒泡階段。
```
此外,事件對象還可能擁有很多其他的屬性,但是他們都是針對特定的`event`的。比如,鼠標事件包含`clientX`和`clientY`屬性來表明鼠標在當前視窗的位置。
另外,`stopPropagation()`方法用于立即停止事件在DOM中的傳播,即取消進一步的事件冒泡或捕獲。
```
var btn = document.getElementById('myDiv');
btn.onclick = function (event) {
alert("clicked");
event.stopPropagation();
};
//避免觸發在document.body上的事件處理程序
document.body.onclick = function (event) {
alert("Body clicked");
};
```
只有在事件處理程序執行期間,`event`對象才會存在,一旦事件處理程序執行完畢,`event`對象就會自動銷毀。
### IE中的事件對象
在`DOM 0`級中添加事件處理程序時,`event`對象是作為`window`對象的一個屬性存在的:
```
var btn = document.getElementById('myDiv');
btn.onclick = function (event) {
var event = window.event;
alert(event.type);//click
};
```
IE 的`event`對象同樣也包含與創建它的事件相關的屬性和方法。
```
cancleBubble 布爾 默認值時false,但可以被設置成true來取消事件冒泡,與dom中的 stopPropagation()方法相同。
returnValue 布爾 默認值是true,當設置成false時用以取消事件的默認行為 與dom中的preventDefault()相同。
srcElement 元素 事件的目標,與dom中的target屬性相同。
type 字符串 被觸發的事件類型。
```
##click事件
當用戶點擊以后,`event`對象會包含以下屬性。
```
pageX,pageY:點擊位置相對于html元素的坐標,單位為像素。
clientX,clientY:點擊位置相對于視口(viewport)的坐標,單位為像素。
screenX,screenY:點擊位置相對于設備顯示屏幕的坐標,單位為設備硬件的像素
```
### clientX,clientY
圖示:`clientX`和`clientY`,他們的值表示事件發生時鼠標指針在視口中的水平和垂直坐標(不包含滾動條區域)

偏移量
```
通過以下4個屬性可以取得元素的偏移量。
(1)offsetHeight:元素在垂直方向上占用的空間大小,以像素計。包括元素的高度、(可見的)水平滾動條的高度、上邊框高度和下邊框高度。
(2)offsetWidth:元素在水平方向上占用的空間大小,以像素計。包括元素的寬度、(可見的)垂直滾動條的寬度、左邊框寬度和右邊框寬度。
(3)offsetLeft:元素的左外邊框至包含元素的左內邊框之間的像素距離。
(4)offsetTop:元素的上外邊框至包含元素的上內邊框之間的像素距離。
```
### pageX,pageY
這兩個屬性表示鼠標光標在頁面中的位置,在頁面沒有滾動的情況下,`pageX`,`pageY`的值與`clientX`,`clientY`的值相等
滾動大小
滾動大小,指的是包含滾動內容的元素的大小。
```
以下是4個與滾動大小相關的屬性。
(1)scrollHeight:在沒有滾動條的情況下,元素內容的總高度。
(2)scrollWidth:在沒有滾動條的情況下,元素內容的總寬度。
(3)scrollLeft:被隱藏在內容區域左側的像素數。通過設置這個屬性可以改變元素的滾動位置。
(4)scrollTop:被隱藏在內容區域上方的像素數。通過設置這個屬性可以改變元素的滾動位置。
```
##焦點事件
焦點事件會在頁面元素獲得或失去焦點時觸發,有以下4個焦點事件:
1. blur:元素失去焦點時觸發,該事件不冒泡
2. focus:元素獲得焦點時觸發。不冒泡
3. focusin:元素獲得焦點時觸發,冒泡
4. focusout:元素失去焦點時觸發,冒泡
##鼠標事件
DOM 3級定義了9個鼠標事件:
1. click:當用戶點擊鼠標主鍵通常是指鼠標左鍵或按回車鍵時觸發。
2. dbclick:用戶雙擊鼠標時觸發
3. mousedown:當用戶按下鼠標任意一個鍵都會觸發,這個事件是不能夠通過鍵盤觸發的。
4. mousemove:當鼠標在某元素周圍移動時重復觸發,該事件不能通過鍵盤事件觸發。
5. mouseout:當鼠標離開元素時觸發,這個事件不能通過鍵盤觸發。
6. mouseover:當鼠標進入元素時觸發,這個事件不能夠通過鍵盤觸發。
7. mouseenter:類似“mouseover”,但不冒泡,而且當光標移到后代元素上不會觸發。
8. mouseleave:類似“mouseout”,但不冒泡。在元素上方是不觸發。
9. mouseup:當用戶釋放鼠標按鍵時觸發,不能夠通過鍵盤觸發。
傳遞給鼠標事件處理程序的事件對象有clientX和clientY屬性,它們指定了鼠標指針相對于包含窗口的坐標。加入窗口的滾動偏移量,就可以把鼠標位置轉換成文檔坐標。
```
頁面上的所有元素都支持鼠標事件。除了`mouseenter`和`mouseleave`外,所有的事件都冒泡,并且他們的默認行為是可以被取消掉的。但取消鼠標事件的默認行為可能會影響到其他事件,因為有些鼠標事件是相互依賴的。
##拖拉事件
(1)`drag`事件
```
drag事件在源對象被拖拉過程中觸發。
```
(2)`dragstart`,`dragend`事件
```
dragstart事件在用戶開始用鼠標拖拉某個對象時觸發,dragend事件在結束拖拉時觸發。
```
(3)`dragenter`,`dragleave`事件
```
dragenter事件在源對象拖拉進目標對象后,在目標對象上觸發。dragleave事件在源對象離開目標對象后,在目標對象上觸發。
```
(4)`dragover`事件
```
dragover事件在源對象拖拉過另一個對象上方時,在后者上觸發。
```
(5)`drop`事件
```
當源對象被拖拉到目標對象上方,用戶松開鼠標時,在目標對象上觸發drop事件。
```
- JavaScript手冊
- Array函數
- String函數
- Date函數
- Mach函數
- Regexp函數
- Location函數
- Window 函數
- Other函數
- History函數
- Navigator函數
- Event函數
- Dom函數
- Json函數
- Sea.js手冊
- JavaScript學習總結
- 1.基礎部分
- 2.對象部分
- 3.BOM和DOM詳解
- 4.function函數部分
- 5.原型和原型鏈詳解
- 6.數據類型和JSON格式
- 7.Ajax和Http狀態字
- 8.正則表達式
- 9.事件詳解
- 前端相關網址
- 前端干貨文章
- JavaScript字符串常用的一些方法
- 前端開發知識體系
- JavaScript速成課
- 移動端開發技巧
- 移動端Web頁面問題解決方案
- 20個常用的CSS技巧
- 學習JavaScript設計模式
- 前端開發學習總結