以下大部分为学习《JavaScript 高级程序设计》(第 3 版) 所做笔记。
目录:
1. DOM中的事件对象
2. IE中的事件对象
3. 跨浏览器的事件对象
Q : 触发DOM上某个事件时产生一个事件对象event,这个对象中包含什么?
A : 包含导致事件的元素、事件的类型以及其他事件相关的信息。包含与创建它的特定事件有关的属性和方法。
Q : 所有浏览器都支持 event 对象吗?
A :都支持。但是支持方式不同。
Q : event 对象什么时候存在?
A : 只有在事件处理程序执行期间,event 对象才会存在。
Q : event 事件什么时候会被销毁?
A :一旦事件处理程序执行完成, event 对象就会被销毁。
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中,无论指定事件处理程序时使用什么方法(DOM0级或者DOM2级),都会传入 event 对象。
点击按钮,控制台输出:
event 的属性与方法
触发 click 事件时产生事件 event ,在控制台输出 event 查看属性和方法:
属性 currentTarget、target
event 对象的 currentTarget 属性表示事件处理程序正在处理事件的那个元素,target 属性表示事件的目标。
在对象处理程序内部,对象 this 始终等于 currentTarget 的值,但是对象 this 并不始终等于 target 的值。
对象 this 并不始终等于 target 的值,举个例子:
点击按钮,控制台输出:
因为事件处理程序注册在 document.body 上,所以 this 跟 currentTarget 都等于 document.body
因为 click 事件真正的元素是按钮元素,所以 target 元素等于按钮元素
属性 type
Q : 什么时候可以使用 type 属性?
A : 需要通过一个函数处理多个事件时
下面举个例子。onclick、onmouseover、onmouseout 事件处理程序注册在按钮上,handler 函数处理多个事件。触发事件时产生一个事件对象 event,通过检测 event 对象的 type 属性让 handler 函数确定发生了什么并且执行相应的操作。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input type="button" id="btn1" value="btn"/> <script> var btn = document.getElementById("btn1"); var handler = function(event){ switch(event.type){ case "click": console.log("按钮被点击"); 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; </script> </body> </html>
preventDefault()方法
preventDefault() 方法能够阻止特定事件的默认行为。前提:cancelable 属性为 true。
举个栗子:链接的默认行为就是被单击时会导航到其 href 特性指定的 URL。可以通过链接的 onclick 事件处理程序取消它。
stopPropagation()方法
stopPropagation() 用于立即停止事件在 DOM 层次中的传播。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input type="button" id="btn1" value="按钮"/> <script> var btn = document.getElementById("btn1"); btn.onclick = function(event){ console.log("btn"); event.stopPropagation(); }; document.body.onclick = function(event){ console.log("document.body"); }; </script> </body> </html>
点击按钮之后,控制台输出:
说明:
点击了按钮,触发了在按钮上注册的事件处理程序,事件处理程序处于目标对象上。如果没有使用 stopPropagation,接下来执行的事件处理程序是冒泡阶段触发的添加到 document.body 中的点击事件。但是使用了 stopPropagation() 函数中止了事件在 DOM 层次上传播,所以没有触发添加到 document.body 上的事件处理程序。
如果没有语句“ event.stopPropagation(); ”,点击按钮之后,控制台会输出:
属性 eventPhase
Q : eventPhase 有啥用?
A :可以用来确定事件当前正位于事件流的哪个阶段。
Q :怎么确定事件当前正位于事件流的哪个阶段?
A :▶eventPhase 为 1 ,在捕获阶段调用事件处理程序
▶eventPhase 为 2 ,事件处理程序处于目标对象上
▶eventPhase 为 3 ,在冒泡阶段调用事件处理程序
下面举个例子:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input type="button" id="btn1" value="按钮"/> <script> var btn = document.getElementById("btn1"); btn.onclick = function(event){ console.log("结果1:", event.eventPhase); //输出:2 }; document.body.addEventListener("click", function(event){ console.log("结果2:", event.eventPhase); //输出:1 }, true); document.body.onclick = function(event){ console.log("结果3:", event.eventPhase); //输出:3 } </script> </body> </html>
点击按钮,控制台输出:
说明:
点击按钮时,首先执行的事件处理程序是捕获阶段触发的添加到 document.body 中的那一个。然后,触发在按钮上注册的事件处理程序。最后,执行的事件处理程序是冒泡阶段触发的添加到 document.body 中的那一个。
(DOM事件流图)
▶ 访问 IE 中的 event 有几种方式,取决于指定事件处理程序的方法。
▶ 使用 DOM0 级方法添加事件处理程序时,event 对象作为 window对象的一个属性存在。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input type="button" id="btn1" value="按钮"/> <script> var btn = document.getElementById("btn1"); btn.onclick = function(){ var event = window.event; //event 对象作为 window 对象的一个属性存在 console.log(event.type); } </script> </body> </html>
通过 HTML 特性指定事件处理程序也可以通过一个名为 event 的变量来访问 event:
点击按钮,控制台输出 event 的属性和方法,下面截取了部分进行说明:
不能认为 this 会始终等于事件目标,因为事件处理程序的作用域是根据指定它的方式来确定的,为了保险最好使用 event.srcElement。
属性 returnValue
returnValue 属性相当于 DOM 中的 preventDefault() 方法,作用都是取消给定事件的默认行为。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <a id="link1" href="http://www.baidu.com">点击跳转百度</a> <script> var link = document.getElementById("link1"); link.onclick = function(){ window.event.returnValue = false; }; </script> </body> </html>
说明:
如果没有设置 returnValue 属性值为 false,点击 “点击跳转百度” 页面会跳转到百度,但是设置了returnValue 属性值为 false 后链接的默认行为被停止了,页面不跳转。
属性 cancelBubble
cancelBubble 属性相当于 DOM 中的 stopPropagation() 方法,作用都是停止事件冒泡。
☆ cancelBubble 只能取消事件冒泡(因为IE不支持事件冒泡)
☆ stopPropagation() 能取消事件捕获与冒泡
举个栗子,不设置 cancelBubble 为 true 时,点击按钮先执行注册在按钮上的点击事件,然后执行在冒泡阶段触发的添加到 document.body 上的点击事件。设置了cancelBubble 为 true 后, 停止了事件冒泡,不执行在冒泡阶段触发的添加到 document.body 上的点击事件。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input type="button" id="btn1" value="按钮"/> <script> var btn = document.getElementById("btn1"); btn.onclick = function(){ console.log("按钮被点击了"); //设置 cancalBubble 为 true,阻止事件冒泡 window.event.cancelBubble = true; }; document.body.onclick = function(){ console.log("body被点击了"); } </script> </body> </html>
点击按钮,控制台输出:
DOM 与 IE 的 event 对象的异同小结
👇
IE 中的 event 对象的全部信息和方法 DOM 对象中都有,但是实现方式不一样
👇
DOM 跟 IE 的 event 对象的属性与方法都会因为事件类型的不同而不同。但是,
DOM 的 event 事件一定会有下面列出的成员:
bubbles cancelable currentTarget defaultPrevented detail eventPhase preventDefault()
stopImmediatePropagation() stopPropagation() target trusted type view
IE 的 event 事件一定会有下面列出的成员:
cancelBubble returnValue srcElement type
👇
DOM 与 IE 相似的属性/方法
基于 DOM 跟 IE 中 event 对象的相似性,可以拿出跨浏览器的方案来。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <input id="btn1" type="button" value="按钮" /> <a id="link1" href="http://www.baidu.com">点击跳转百度</a> <script> var EventUtil = { //视情况分别使用 DOM0 级方法、DOM2 级方法或 IE 方法来添加事件 addHandler: function(element, type, handler){ if(element.addEventListener){ element.addEventListener(type, handler, false) }else if(element.attachEvent){ element.attachEvent("on"+type, handler); }else{ element["on"+type] = handler; } }, //返回对 event 的引用 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){ if(element.removeEventListener){ element.removeEventListener(type, handler, false) }else if(element.detachEvent){ element.detachEvent("on"+type, handler); }else{ element["on"+type] = null; } }, //阻止事件流 //因为 IE不支持事件捕获,所以在跨浏览器情况下也只能用于阻止事件冒泡 stopPropagation: function(event){ if(event.stopPropagation){ event.stopPropagation(); }else{ event.cancelBubble = true; } } }; var btn = document.getElementById("btn1"); btn.onclick = function(event){ event = EventUtil.getEvent(event); console.log( "event:", event ); console.log( "事件的引用:", EventUtil.getTarget(event) ); console.log( "事件的目标:", EventUtil.getTarget(event) ); //阻止事件流 //点击按钮不会执行在冒泡阶段触发的添加到 document.body 的事件处理程序 EventUtil.stopPropagation(event); } document.body.onclick = function(event){ console.log("body 被点击了"); } var link = document.getElementById("link1"); link.onclick = function(event){ event = EventUtil.getEvent(event); //阻止链接的默认行为 EventUtil.preventDefault(event); } </script> </body> </html>
点击链接,没有跳转页面。点击按钮,控制台输出:
说明:
• 将 event = EventUtil.getEvent(event) 添加到事件处理程序的开头,就可以确保随时都能使用 event 对象,而不用担心用户使用的是什么浏览器。
• EventUtil 的 stopPropagation() 方法在跨浏览器的情况下,也只能用来阻止事件冒泡,因为 IE 不支持事件捕获。