事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象(Event Object),这个对象中包含着所有与事件有关的属性和方法。该对象会作为第一个参数传递给监听函数。

  • DOM 事件模型中的事件对象常用属性方法
    • type:用于获取事件类型
    • target:获取事件目标
    • stopPropagation():阻止事件冒泡
    • preventDefault():阻止默认行为
  • IE 事件模型中的事件对象常用属性方法
    • type:用于获取事件类型
    • srcElement:获取事件目标
    • cancelBubble:阻止事件冒泡
    • returnValue:阻止事件默认行为

DOM 中的事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0 级或 DOM2 级),都会传入 event 对象。

以这种方式提供 event 对象,可以让 HTML 特性事件处理程序与 JavaScript 函数执行相同的操作。event 对象包含与创建它的特定事件相关的属性和方法。触发的事件类型不一样。不过,所有事件都会有下表列出的成员。

属性/方法类型读/写说明
bubblesBoolean只读表明事件是否冒泡
cancelableBoolean只读表明是否可以取消事件的默认行为
currentTargetElement只读其事件处理程序当前正在处理事件的那个元素
defaultPreventedBoolean只读true 表示已经调用了 preventDefault()(DOM3 级事件中新增)
detailInteger只读与事件相关的细节信息
eventPhaseInteger只读调用事件处理程序的阶段:1 表示捕获阶段,2 表示“处于目标”,3 表示冒泡阶段
preventDefault()Function只读取消事件的默认行为。如果 cancelabletrue,则可以使用这个方法。
stopImmediatePropagation()Function只读取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3 级事件中新增)
stopPropagation()Function只读取消事件的进一步捕获或冒泡。如果 bubbles 为 true,则可以使用这个方法
targetElement只读事件的目标
trustedBoolean只读true 表示事件是浏览器生成的。为 false 表示事件是由开发人员通过 JavaScript 创建的(DOM3 级事件中新增)
typeString只读被触发的事件的类型
viewAbstractView只读与事件关联的抽象视图。等同于发生事件的 window 对象

事件处理程序内部 this 指向

在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 tartget 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 thiscurrentTargettartget 包含相同的值。

// Example
var btn = doocument.getElementById('myBtn');
btn.onclick = function(event) {
alert(event.currentTarget === this); // true
alert(event.target === this); // true
};

当单击这个例子中的按钮时,thiscurrentTarget 都等于 document.body,因为事件处理程序是注册到这个元素上的。然而,target 元素却等于按钮元素,因为它是 click 事件真正的目标。由于按钮上并没有注册事件处理程序,结果 click 事件就冒泡到了 document.body,在那里事件才得到了处理。

单函数处理多事件

在需要通过一个函数处理多个事件时,可以使用 type 属性。例如:

var btn = document.getElementById('myBtn');
var handler = function(event) {
switch (event.type) {
case 'click':
alert('Clicked');
break;
case 'mouseover':
event.target.style.backgroundColor = 'red';
break;
case 'mouseout':
event.target.style.backgroundColor = '';
break;
}
};
btn.onclick = handler;
btn.mouseover = handler;
btn.mouseout = handler;

这个例子定义了一个名为 handler 的函数,用于处理 3 种事件:clickmouseovermouseout。当单击按钮时,会出现一个与前面例子中一样的警告框。当按钮移动到按钮上面时,背景颜色应该会变成红色,而当鼠标移动出按钮的范围时,背景颜色应该会恢复为默认值。这里通过检测 event.type属性,让函数能够确定发生了什么事件,并执行相应的操作。

阻止浏览器默认行为

要阻止特定事件的默认行为,可以使用 preventDefault() 方法。例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的 onclick 事件处理程序可以取消它。

var link = document.getElementById('myLink');
link.onclick = function(event) {
// 阻止鼠标的默认行为
event.preventDefault();
};

只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault()来取消其默认行为。

阻止事件冒泡

stopPropagation() 方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。

function stopPropagation(e) {
const event = e || window.event;
event.stopPropagation ? event.stopPropagation() : (window.event.cancelBubbl = true);
}

⚠️ 只有在事件处理程序执行期间,event 对象才会存在。一旦事件处理程序执行完成,event 对象就会被销毁。

跨浏览器的事件对象

虽然 DOM 和 IE 中的 event 对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。IE 中 event 对象的全部信息和方法 DOM 对象中都有,只不过实现方式不一样。不过,这种对应关系让实现两种事件模型之间的映射非常容易。可以对前面介绍的 EventUtil 对象加以增强,添加如下方法以求同存异。

const EventUtil = {
addHandler: function(element, type, handler) {
// 省略的代码
}
getEvent: function(event) {
return event ? event : window.event;
}
getTarget: function(event) {
return event.target || event.srcElement;
}
preventDefault: function(event) {
if (event.preventDefault){
event.preventDefault();
} else {
event.returnValue = false;
}
}
removeHandler: function(element, type, handler) {
// 省略的代码
}
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation;
} else {
event.cancelBubble = true;
}
}
}

参考资料: