事件对象
在触发 DOM 上的某个事件时, 会产生一个事件对象 event, 这个对象中包含着所有与事件有关的信息. 包括导致事件的元素, 事件的类型以及其他与特定事件相关的信息.
DOM 中的事件对象
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中. 无论指定事件处理程序时使用什么方法 (DOM0 级或 DOM2 级), 都会传入 event 对象.
- var btn = document.getElementById('myBtn');
- btn.onclick = function (event) {
- alert(event.type) //'click'
- }
- btn.addEventListener('click', function (event) {
- alert(event.type) //'click'
- }, false);
这个例子中的两个事件处理程序都会弹出一个警告框, 显示由 event.type 属性表示的事件类型. 这个属性始终都会包含被触发的事件类型.
event 对象包含与创建它的特定事件有关的属性和方法. 触发的事件类型不一样, 可用的属性和方法也不一样. 不过, 所有事件都会有下表列出的成员.
属性 / 方法 | 类型 | 读 / 写 | 说明 |
---|---|---|---|
preventDefault() | Function | 只读 | 取消事件的默认行为。如果 cancelable 是 true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。同时阻止任何事件处理程序被调用(DOM3 级事件中新增) |
stopPropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。如果 bubbles 为 true,则可以使用这个方法 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为 true 表示事件是浏览器生成的。为 false 表示事件是由开发人员通过 Javascript 创建的(DOM3 级事件中新增) |
type | String | 只读 | 被触发的事件的类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的 window 对象 |
看下面例子:
- document.body.onclick = function (event) {
- alert(event.currentTarget === document.body); // true
- alert(this === document.body) // true
- alert(event.target === document.getElementById('myBtn')); // true
- };
当单击这个例子中的按钮时, this 和 currentTarget 都等于 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.onmouseover = handler;
- btn.onmouseout = handler;
要阻止特定事件的默认行为, 可以使用 preventDefault() 方法. 例如, 链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL. 如果你想阻止链接导航这一默认行为, 那么通过链接 onclick 事件处理程序可以取消它.
只有 cancelable 属性设置为 true 的事件, 才可以使用 preventDefault() 来取消其默认行为.
另外, stopPropagation() 方法用于立即停止事件在 DOM 层次中的传播, 即取消进一步的事件捕获或冒泡. 例如, 直接添加到一个按钮的事件处理程序可以调用 stopPropagation(), 从而避免触发注册在 document.body 上面的事件处理程序, 如下面的例子所示.
事件对象的 eventPhase 属性, 可以用来确定事件当前正位于事件流的哪个阶段. 如果是在捕获阶段调用的事件处理程序, eventPhase 等于 1; 如果事件处理程序处于目标对象上, 则 eventPhase 等于 2; 如果在冒泡阶段调用的事件处理程序, eventPhase 等于 3.
注意, 尽管 "处于目标" 发生在冒泡阶段, 但 eventPhase 仍然一直等于 2.
当 eventPhase 等于 2 时, this,target 和 currentTarget 始终是相等的.
只有在事件处理程序执行期间, event 对象才会存在; 一旦事件处理程序执行完成, event 对象就会被销毁.
IE 中的事件对象
与访问 DOM 中的 event 对象不同, 要访问 IE 中的 event 对象有几种不同的方式, 取决于指定事件处理程序的方法. 在使用 DOM0 级方法添加事件处理程序时, event 对象作为 window 对象的一个属性存在. 来看下面的例子.
- var btn = document.getElementById('myBtn');
- btn.onclick = function () {
- var event = window.event;
- alert(event.type) //'click'
- }
可是, 如果事件处理程序是使用 attachEvent() 添加的, 那么就会有一个 event 对象作为参数被传入事件处理程序函数中, 如下所示.
- var btn = document.getElementById('myBtn');
- btn.attacehEvent('onclick', function (event) {
- alert(event.type); //'click'
- })
在像这样使用 attachEvent() 情况下, 也可以通过 window 对象来访问 event 对象, 就像使用 DOM0 级方法时一样. 不过为方便起见, 同一个对象也会作为参数传递.
如果是通过 html 特性指定的事件处理程序, 那么还可以通过一个名叫 event 的变量来访问 event 对象 (与 DOM 中的事件模型相同).
<input type='button' value='Click Me' onclick='alert(event.type)'>
IE 的 event 对象同样也包含与创建它的事件相关的属性和方法. 其中很多属性和方法都有对应的或者相关的 DOM 属性和方法. 与 DOM 的 event 对象一样, 这些属性和方法也会因为事件类型的不同而不同, 但所有事件对象都会包含下表所列的属性和方法.
属性 / 方法 | 类型 | 读 / 写 | 说明 |
---|---|---|---|
cancelBubble | Boolean | 读 / 写 | 默认值 false,但将其设置为 true 就可以取消事件冒泡(与 DOM 中的 stopPropagation() 方法的作用相同) |
returnValue | Boolean | 读 / 写 | 默认值为 true,将其设置为 false 就可以取消事件的默认行为(与 DOM 中的 preventDefault() 方法的作用相同) |
srcElement | Element | 只读 | 事件的目标(与 DOM 中的 target 属性相同) |
type | String | 只读 | 被触发的事件的类型 |
因为事件处理程序的作用域是根据指定它的方式来确定的, 所以不能认为 this 会始终等于事件目标. 故而, 最好还是使用 event.srcElement 比较保险.
跨浏览器的事件对象
虽然 DOM 和 IE 中的 event 对象不同, 但基于它们之间的相似性依旧可以拿出跨浏览器的方案来. IE 中 event 对象的全部信息和方法 DOM 对象中都有, 只不过实现方式不一样. 不过, 这种对应关系让实现两种事件模型之间的映射非常容易. 可以对前面介绍的 EventUtil 对象加以增强, 添加如下方法以求同存异.
- var EventUtil = {
- addHandler: function (element, type, handler) {},
- removeHandler: 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;
- }
- },
- stopPropagation: function (event) {
- if (event.stopPropagation) {
- event.stopPropagation();
- } else {
- event.cancelBubble = true;
- }
- }
- }
跨浏览器阻止事件冒泡:
- var btn = document.getElementById('myBtn');
- btn.onclick = function (event) {
- alert('Clicked');
- event = EventUtil.getEvent(event);
- EventUtil.stopPropagation(event);
- }
- document.body.onclick = function (event) {
- alert('Body clicked');
- }
来源: https://juejin.im/post/5aebd7a8f265da0b7527f9a4