JavaScript Dom 事件模型

1.事件模型

DOM 事件级别:
DOM0 element.onclick=function(){}
DOM1 标准没有涉及事件的提案。
DOM2 element.addEventListener(‘click’,function(){},false)
DOM3 element.addEventListener(‘keyup’,function(){},false) //增加了更多类型

事件模型:捕获(上到下), 冒泡(下到上)
事件流: 捕获 目标阶段 冒泡
描述 DOM 事件捕获的具体流程:window -> document -> html -> body -> … -> 目标元素/ev。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
*event: 字符串,指定事件名
*function: 指定要事件触发时执行的函数
*useCapture: 布尔值,指定事件是否在捕获或冒泡阶段执行
*/
//事件监听
element.addEventListener(event, function, useCapture)
//移除事件监听:
element.removeEventListener(event, function, useCapture)
//IE8 及更早(目标阶段-冒泡阶段)
//事件监听:
element.attatchEvent(event, function)
//移除事件监听:
element.detachEvent(event, function)

2.事件对象

DOM事件模型中的事件对象常用属性:

  1. type // 用于获取事件类型
  2. target // 获取事件目标(当前被点击的元素)
  3. stopPropagation() // 阻止事件冒泡
  4. preventDefault() // 阻止默认事件
  5. currentTarget //当前绑定的事件
  6. stopImmediatePropagation() //A中阻止B执行(事件响应优先级)

IE事件模型中的事件对象常用属性:

  1. type // 用于获取事件类型
  2. srcElement //获取事件目标
  3. cancelBubble //阻止事件冒泡
  4. returnValue //阻止事件默认行为

3.事件委托/代理

优势:

  • 省内存减少事件注册,
  • 新增子对象时无需再次对其绑定事件,适合动态添加元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul id="parent">
<li class="child">one</li>
<li class="child">two</li>
<li class="child">three</li>
</ul>
<script type="text/javascript">
//父元素
var dom = document.getElementById('parent');
//父元素绑定事件,代理子元素的点击事件
dom.onclick= function(event) {
var event= event || window.event;
var curTarget= event.target || event.srcElement;
if (curTarget.tagName.toLowerCase() == 'li') {
//事件处理
}
}
</script>

4.实现事件模型

编写 bind 绑定,trigger 触发函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function Emitter() {
//_listener[自定义的事件名]= [所用执行的匿名函数1,所用执行的匿名函数2,...]
this._listener= [];
};

Emitter.prototype.bind= function(eventName, handle) {
//是否存在eventName事件,否则新建数组
var listener= this._listener[eventName] || [];
listener.push(handle);
this._listener[eventName]= listener;
};

Emitter.prototype.trigger= function(eventName) {
//取得除eventName之外的其他参数
var args= Array.prototype.slice.apply(arguments).slice(1);
var listener= this._listener[eventName];
if (!Array.isArray(listener)) {
return false;
};
//遍历事件
listener.forEach(function(handleFun) {
try{
handleFun.apply(this, args);
}catch (e){
console.error(e);
}
});
};

// 实例
var emitter= new Emitter();
// 绑定函数
emitter.bind('output', function(arguments_1, arguments_2) {
console.log(arguments_1, arguments_2);
});
//触发函数
emitter.trigger('output', 'a', 'b');

5.事件广播

1
2
3
4
5
// 自定义事件
var event= new Event('custome');
element.addEvenetListener('custome', function(e) {...}, false);
element.dispatchEvent(event);
// CustomEvent 区别:CustomEvent 后加 object 指定一些数据,参数自定义

Reference:
https://javascript.ruanyifeng.com/dom/event.html
https://www.cnblogs.com/pcd12321/p/5223347.html
https://segmentfault.com/a/1190000006934031#articleHeader10
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events