[TOC]
DOM是和HTML文檔關聯的東西,其實很js沒有本質的關系,只是js很多時候用來處理dom而已。
此外為了方便js操作dom,有一些框架庫可以選用,比如jquery。
# DOM0級事件處理方式:
通過javascript制定事件處理程序的傳統方式。就是將一個函數賦值給一個事件處理屬性。第四代web瀏覽器出現,至今為所有瀏覽器所支持。優點,簡單且具有跨瀏覽器的優勢。
例:
~~~
var btn = document.getElementById("btn");
btn.onclick = function(){
alert(this.id);//this指定當前元素btn
}
~~~
或者
`<input onclick="alert(1)" />`
刪除DOM0事件處理程序,只要將對應事件屬性置為`null`即可。
~~~
btn.onclick = null;
~~~
缺點:一個事件處理程序只能對應一個處理函數。
* DOM2 是通過`addEventListener`綁定的事件,還有 IE 下的 DOM2 事件通過`attachEvent`綁定;
* DOM3 是一些新的事件,區別 DOM3 和 DOM2 的方法我感覺是 DOM3 事件有分大小寫的,DOM2 沒有;
# 事件流

IE的事件流是冒泡, 從里面往上面冒, netscape是從外部元素往內部元素捕獲;
而**DOM2級的事件規定了事件流包含三個階段**包括:
* 1:事件捕獲
* 2:處于目標階段
* 3:事件冒泡階段
(IE8以及更早版本不支持DOM事件流);
## 捕獲和冒泡
~~~
<div id="div1">
<div id="div2"></div>
</div>
<script>
let div1 = document.getElementById('div1');
let div2 = document.getElementById('div2');
div1.onClick = function(){
alert('1')
}
div2.onClick = function(){
alert('2');
}
</script>
~~~
> 當點擊`div2`時,會彈出兩個彈出框。在`ie8/9/10`、`chrome`瀏覽器,會先彈出”2” 再彈出 “1”,這就是事件冒泡:事件從最底層的節點向上冒泡傳播。
> 綁定在被點擊元素的多個事件是按照代碼順序發生,其他元素通過冒泡或者捕獲 “感知” 的事件,按照 W3C 的標準,先發生捕獲事件,后發生冒泡事件。所有事件的順序是:其他元素捕獲階段事件 -> 本元素代碼順序事件 -> 其他元素冒泡階段事件 。
> `addEventListener`的第三個參數(`useCapture`參數默認值為`false`)決定把事件發生時機是在捕獲階段(`true`)還是冒泡階段 (`false`)。
# DOM2級事件處理方式
DOM2級事件處理方式指定了,添加事件處理程序和刪除事件處理程序的方法。分別是:
```
addEventListener(eventName,func,isPuhuo);
removeEventListener(eventName,func,isPuhuo);
```
例如:
```
var btn = document.getElementById("btn");
handler = function(){
……
}
addEventListener("click",handler,false/true);
removeEventListener("click",handler,false/true);
```
參數分別是,事件處理屬性名稱,處理函數,是否在捕獲時執行事件處理函數。
注:
1. `eventName`的值均不含 `on`,例如注冊鼠標點擊事件 eventName 為 `click`;
2. 處理函數中的 `this` 依然指的是指當前dom元素( [addEventListener 回調中的 this 指向](https://www.jianshu.com/p/4943571dcac5));
3. 通過 `addEventListener` 添加的事件處理程序,只能通過 `removeEventListener` 來刪除,也就是說通過 `addEventListener` 添加的匿名函數將無法被刪除。
```
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
alert(this.id);
}, false);
btn.removeEventListener("click", function () { //無效!
alert(this.id);
}, false);
```
## 事件對象

# IE中的DOM2級事件處理
IE 中的 DOM2 級事件處理使用了 `attachEvent` 和 `detachEvent` 來實現。這倆個方法接受倆個相同的參數,事件處理名稱和事件處理函數。IE8 級更早版本只支持冒泡型事件,所以attachEvent添加的事件都會被添加到冒泡階段。
例如:
```
var btn = document.getElementById("btn");
btn.attachEvent("onclick",function(){
alert(this);//此處this是window
});
```
注意;通過 `attachEvent` 添加的事件第一個參數是 `onclick` 而非標準事件中的 `click` 。在使用 `attachEvent` 方法和 DOM0 級事件處理程序的主要區別在于事件處理程序的作用域。采用DOM0級處理方式,事件處理程序會在其所屬元素的作用域內運行。使用 `attachEvent` ,事件處理程序會在全局作用域內運行,因此 `this` 等于 `window` 。
## 怎么移除匿名函數?
啊哈哈哈,我知道問題出在哪了,也知道 `arguments.callee`(嚴格模式禁止) 到底是什么了!原來在函數內,`arguments.callee` 是指本函數,也就是函數自身,所以以下會在控制臺輸出函數 `aa`(toString 后也就是函數的代碼)。
```
(function aa() {
console.log(arguments.callee);
}());
```
而我要的函數不是這個,而是綁定到 `click` 的函數,所以代碼應該改成這樣:
```
var i = 0;
function init() {
aabtn.addEventListener("click", function(e) { aa(arguments.callee); });
}
function aa(fun) {
tex.innerHTML = i++;
aabtn.removeEventListener("click", fun);
}
```
>參考:https://segmentfault.com/q/1010000002462675
### 3、DOM3事件
DOM瀏覽器中可能發生的事件有很多種,不同事件類型具有不同的信息,DOM3級事件規定了一下幾種事件:
UI事件,當用戶與頁面上的元素交互時觸發;
焦點事件,當元素獲得或者失去焦點時觸發;
鼠標事件,當用戶通過鼠標在頁面上執行操作時觸發;
滾輪事件,當使用鼠標滾輪(或類似設備)時觸發;
文本事件,當在文檔中,輸入文本時觸發;
鍵盤事件,當用戶通過鍵盤在頁面上執行操作時觸發;
合成事件,當為IME(Input Method Editor,輸入法編輯器)輸入字符時觸發;
變動事件,當底層Dom結構發生變化時觸發;
DOM3級事件模塊在DOM2級事件的基礎上重新定義了這些事件,也添加了一些新事件。包括IE9在內的主流瀏覽器都支持DOM2級事件,IE9也支持DOM3級事件。
DOM中的事件模擬(自定義事件):
DOM3級還定義了自定義事件,自定義事件不是由DOM原生觸發的,它的目的是讓開發人員創建自己的事件。
事件對象`event`下的屬性和方法:
```
因為各個瀏覽器的事件對象不一樣, 把主要的時間對象的屬性和方法列出來;
bubble : 表明事件是否冒泡
cancelable : 表明是否可以取消冒泡
currentTarget : 當前時間程序正在處理的元素, 和this一樣的;
defaultPrevented: false ,如果調用了preventDefualt這個就為真了;
detail: 與事件有關的信息(滾動事件等等)
eventPhase: 如果值為1表示處于捕獲階段, 值為2表示處于目標階段,值為三表示在冒泡階段
target || srcElement: 事件的目標
trusted: 為ture是瀏覽器生成的,為false是開發人員創建的(DOM3)
type : 事件的類型
view : 與元素關聯的window, 我們可能跨iframe;
preventDefault() 取消默認事件;
stopPropagation() 取消冒泡或者捕獲;
stopImmediatePropagation() (DOM3)阻止任何事件的運行;
//stopImmediatePropagation阻止 綁定在事件觸發元素的 其他同類事件的callback的運行
IE下的事件對象是在window下的,而標準應該作為一個參數, 傳為函數第一個參數;
IE的事件對象定義的屬性跟標準的不同,如:
cancelBubble 默認為false, 如果為true就是取消事件冒泡;
returnValue 默認是true,如果為false就取消默認事件;
srcElement, 這個指的是target, Firefox下的也是srcElement;
```
# 參考
[史上最詳細的JavaScript事件使用指南](http://www.admin10000.com/document/6293.html)
[JavaScript 和事件](https://yujiangshui.com/javascript-event/)
小胡子的 [[解惑]JavaScript事件機制](http://www.cnblogs.com/hustskyking/p/problem-javascript-event.html)
葉小釵的[【探討】javascript事件機制底層實現原理](http://www.cnblogs.com/yexiaochai/p/3477715.html)
- 步入JavaScript的世界
- 二進制運算
- JavaScript 的版本是怎么回事?
- JavaScript和DOM的產生與發展
- DOM事件處理
- js的并行加載與順序執行
- 正則表達式
- 當遇上this時
- Javascript中apply、call、bind
- JavaScript的編譯過程與運行機制
- 執行上下文(Execution Context)
- javascript 作用域
- 分組中的函數表達式
- JS之constructor屬性
- Javascript 按位取反運算符 (~)
- EvenLoop 事件循環
- 異步編程
- JavaScript的九個思維導圖
- JavaScript奇淫技巧
- JavaScript:shim和polyfill
- ===值得關注的庫===
- ==文章==
- JavaScript框架
- Angular 1.x
- 啟動引導過程
- $scope作用域
- $q與promise
- ngRoute 和 ui-router
- 雙向數據綁定
- 規范和性能優化
- 自定義指令
- Angular 事件
- lodash
- Test