[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 没有;
# 事件流
![](https://box.kancloud.cn/315d2fca5b0dbbc55e451294c31a1587_394x357.png)
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);
```
## 事件对象
![](https://img.kancloud.cn/4c/cb/4ccb9a70d4b97f028d05769701a7f067_728x893.png)
# 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