持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
事件流
在JavaScript中的事件可以看出是和HTML和浏览器中的一种交互操作,而HTML是一种DOM树结构,在绑定父子节点事件后,触发事件时会有一个先后顺序问题,就是事件流概念。
事件流三个阶段:
- 捕获阶段(从上到下)
- 事件处于目标触发阶段
- 冒泡阶段(从下到上)
事件模型
原始事件模型(DOM0)
在HTML中直接绑定
<input type="button" onclick="fun()">
// 或
var btn = document.getElementById('.btn');
btn.onclick = fun;
特性:
- 只能绑定一次,后绑定的事件会覆盖之前的事件
- 只支持冒泡,不支持捕获
- 删除时只需要将对应事件置为null就行
btn.onclick = null; - 兼容性好
标准事件模型
在标准事件模型中,包含三个阶段。
方式:
- 绑定:
addEventListener(eventType, handler, useCapture) - 移除:
removeEventListener(eventType, handler, useCapture)
参数如下:
eventType指定事件类型(不要加on)handler是事件处理函数useCapture是一个boolean用于指定是否在捕获阶段进行处理,一般设置为false与IE浏览器保持一致
特性:
- 支持多个事件
IE事件模型
IE事件模型只支持事件处理阶段和事件冒泡阶段。
方式:
- 绑定:
attachEvent(eventType, handler)// onclick - 移除:
detachEvent(eventType, handler)
事件对象Event
事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。
Event.preventDefault方法取消浏览器对当前事件的默认行为。该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用stopPropagation()或stopImmediatePropagation()方法。Event.stopPropagation()方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。Event.stopImmediatePropagation方法阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。Event.cancelBubble属性是一个布尔值,如果设为true,相当于执行Event.stopPropagation(),可以阻止事件的传播。Event.returnValue阻止事件默认行为Event.target属性返回原始触发事件的那个节点,即事件最初发生的节点。Event.currentTarget属性返回事件当前所在的节点,即事件当前正在通过的节点,也就是当前正在执行的监听函数所在的那个节点。随着事件的传播,这个属性的值会变。
如何手写一个事件监听工具函数
const EventUtil = {
addEvent: function (element, type, handler) {
if (element.addEventListener) {
// 支持 DOM2 级事件,优先使用
element.addEventListener(type, handler)
} else if (element.attachEvent) {
// 支持 IE 事件模型
element.attachEvent('on' + type, handler)
} else {
// 兼容性处理
element['on' + type] = handler;
}
},
removeEvent: function (element, type, handler) {
if (element.removeEventListener) {
// 支持 DOM2 级事件,优先使用
element.removeEventListener(type, handler)
} else if (element.detachEvent) {
// 支持 IE 事件模型
element.detachEvent('on' + type, handler)
} else {
// 兼容性处理
element['on' + type] = null;
}
},
getTarget: function(event) {
return event.target || event.srcElement;
},
currentTarget: function(event) {
return event.currentTarget;
},
stopPropogation: function(event) {
if (event.stopPropogation) {
event.stopPropogation();
}
event.cancelBubble = true
},
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
}
event.returnValue = false
},
}
事件委托
什么是事件委托?
简单的说,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素。
真正绑定事件的是外层元素,而不是目标元素。当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
事件委托的应用场景?
我们有大量列表项,需要对每一项进行事件绑定处理,当我们新增或删除一个列表项时,就要对新增的元素绑定事件,给即将删去的元素解绑事件,这就很麻烦,而且内存消耗是非常大的。所以,这个时候我们就可以用事件委托,把事件绑定在他们公共的父级上,然后执行事件的时候再去匹配目标元素。
事件委托有哪些优点和缺点?
优点:
- 减少整个页面所需的内存,提升整体性能
- 动态绑定,减少重复工作
缺点:
- 只能对有冒泡机制的事件进行委托,而
focus、blur这些事件没有事件冒泡机制,所以无法进行委托绑定事件。 mousemove、mouseout这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的