事件流描述的是从页面中接收事件的顺序.IE的事件流为事件冒泡流,而网景浏览器为事件捕获流.
事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).例如:
<html> <head> <title>Event Bubbling Example</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html>
则click事件的传播顺序如下:
而事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件,其传播顺序如下:
DOM2级事件规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段.事件捕获为捕获事件提供了机会,然后是实际的目标接收到事件,最后的冒泡阶段对事件作出响应.
事件就是用户或浏览器自身执行的某种动作,响应某个事件的函数为事件处理程序,以"on"开头.
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定.这个特性的值应该是能够执行的javascript代码.例如:
<input type="button" value="Click Me" onClick="document.write('hello world')"/>
但是在HTML中定义的事件处理程序可以包含要执行的具体动作(有权访问全局作用域中的任何代码):
<html> <script type="text/javascript"> function showMessage() { document.write("Hello world!"); } </script> <body> <input type="button" value="Click Me" onClick="showMessage()"/> </body> </html>
这样指定事件处理程序具有一些独到之处.因为这样会创建一个封装着元素属性值的函数,而这个函数有一个局部变量event,也就是事件对象:
<input type="button" value="Click Me" onClick="alert(event.type)"/>
HTML事件处理程序的缺点:
1. 存在一个时差问题.因为用户可能会在HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件.通常使用try--catch来捕获异常.
2. 这样扩展事件处理程序的作用域链在不同浏览器中会导致不同的结果.
3. HTML与JavaScript代码紧密耦合,不好修改代码.
通过JavaScript指定事件处理程序的传统方法,就是将一个函数赋值给一个事件处理程序的属性.每个元素都有自己的事件处理程序属性.例如:
<html><body> <input id="myBtn" type="button" value="Click Me" /> <!-- 这里onclick必须在按钮初始化完成后--> <script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.onclick = function() { alert("Clicked"); alert(this.id); }; </script> </body></html>
使用DOM0级方法指定的事件处理程序被认为是元素的方法.因此,这时候的事件处理程序是在元素的作用域中运行;则程序中的this引用当前的元素,甚至可以通过this访问元素的任何属性和方法.
我们可以指定属性为空,则删除事件处理程序:
btn.onclick = null; //删除事件处理程序
相比于HTML事件处理程序,JavaScript指定事件处理程序的优势是:
1. 简单.
2. 跨浏览器.
DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener().所有DOM节点中都包含这两个方法,并且它们都接受三个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值.最后这个布尔值参数是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序(一般都是冒泡阶段来处理事件):
<input id="myBtn" type="button" value="Click Me" /> <!-- 这里onclick必须在按钮初始化完成后--> <script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.addEventListener("click", function(){ alert(this.id); }, false); </script>
而DOM2级事件的好处是可以添加多个事件处理程序(DOM0级事件处理程序无法办到):
<script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.addEventListener("click", function(){ alert(this.id); }, false); btn.addEventListener("click", function(){ alert("Hello world!"); }, false); </script>
事件处理会按照它们添加的顺序触发.通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时候传入的参数与添加处理程序时使用的参数相同.这就意味着通过addEventListener()添加的匿名函数将无法移除:
<script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.addEventListener("click", function(){ alert(this.id); }, false); //移除失败!因为匿名函数不相等 btn.removeEventListener("click", function(){ alert(this.id); }, false) </script>
我们可以修改如下:
<script type="text/javascript"> var handler = function() { alert(this.id); }; var btn = document.getElementById("myBtn"); btn.addEventListener("click", handler, false); //移除失败!因为匿名函数不相等 btn.removeEventListener("click", handler, false) </script>
这时候我们单击不会弹出警告按钮,因为事件被移除了.
IE提供与DOM类似的两个方法:attachEvent()和detachEvent().它们接受两个参数:事件处理程序名称和事件处理程序函数.它与DOM2级事件处理程序有以下不同:
1. 事件处理程序会在全局作用域中运行(而DOM是在元素的作用域中运行)
2. 添加不同的事件处理程序后,是以相反的顺序被触发的(和DOM是完全相反)
3. 事件处理程序以on开头
<script type="text/javascript"> var handler = function() { alert(this.id); }; var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", handler); </script>
<script type="text/javascript"> var EventUtil = { addHandler : function(element, type, handler) { //DOM2 if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, removeHandler : function(element, type, handler) { //DOM2 if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } }; </script>
而我们可以这样使用EventUtil对象:
var btn = document.getElementById("myBtn"); var handler = function() { alert("clicked"); }; EventUtil.addHandler(btn,"click", handler); //省略其他代码 EventUtil.removeHandler(btn, "click", handler);
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素,事件的类型以及其他特定事件相关的信息.
兼容DOM的浏览器会将一个event对象传入到事件处理程序中.无论指定事件处理程序时使用什么方法(DOM0/DOM2),都会传入event对象:
<html><body> <script type="text/javascript" src="./print.js"></script> <!--这里HTML的事件处理会被DOM所覆盖--> <input id="myBtn" type="button" value="Click Me" onClick="alert(event.type + ' HTML')"/> <!-- 这里onclick必须在按钮初始化完成后--> <script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.onclick = function(event) { alert(event.type + " DOM0"); }; btn.addEventListener("click", function(event){ alert(event.type + " DOM2"); }, false); </script> </body></html>
这里程序只会弹出DOM0和DOM2,而HTML的并未弹出.
event对象包含与创建它的特定事件有关的属性和方法.触发的事件类型不一样,可用的属性和方法也不一样.不过,所有事件都会有下表列出的成员:
属性/方法 |
类型 |
读/写 |
说明 |
bubbles |
Boolean |
只读 |
表明事件是否冒泡 |
cancelable |
Boolean |
只读 |
表明是否可以取消事件的默认行为 |
currentTarget |
Element |
只读 |
其事件处理程序当前正在处理事件的那个元素 |
defaultPrevented |
Boolean |
只读 |
为true表示已经调用了preventDefault()(DOM3级事件中新增) |
detail |
Integer |
只读 |
与事件相关的细节信息 |
eventPhase |
Integer |
只读 |
调用事件处理程序的阶段:1表示捕获阶段,2表示处于目标,3表示冒泡阶段 |
preventDefault() |
Function |
只读 |
取消事件的默认行为.如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() |
Function |
只读 |
取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件中新增) |
stopPropagation() |
Function |
只读 |
取消事件的进一步捕获或冒泡.如果bubbles为true,则可以使用这个方法 |
target |
Element |
只读 |
事件的目标 |
trusted |
Boolean |
只读 |
为true表示事件是浏览器生成的.为false表示事件是由开发人员通过javascript创建的.(DOM3级事件中新增) |
type |
String |
只读 |
被触发的事件类型 |
view |
AbstractView |
只读 |
与事件关联的抽象视图.等同于发生事件的window对象. |
提供一个实例:
<html><body> <!--这里HTML的事件处理会被DOM所覆盖--> <input id="myBtn" type="button" value="Click Me" /> <!-- 这里onclick必须在按钮初始化完成后--> <script type="text/javascript"> function handler(event) { debugger; document.write(event.type); } var btn = document.getElementById("myBtn"); btn.onclick = handler; </script> </body></html>而通过firebug调试时候可以发现:
在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标.如果直接将事件处理程序指定给了目标元素,则this,currentTarget和target包含相同的值:
<html><body> <script type="text/javascript" src="./print.js"></script> <!--这里HTML的事件处理会被DOM所覆盖--> <input id="myBtn" type="button" value="Click Me"/> <!-- 这里onclick必须在按钮初始化完成后--> <script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.onclick = function(event) { //this为当前对象 //currentTarget为事件处理程序当前正在处理事件的元素 //target为事件的目标 alert(event.currentTarget === this); //true alert(event.target === this); //true }; document.body.onclick = function(event) { alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(event.target === document.getElementById("myBtn")); //true }; </script> </body></html>
在需要通过一个函数处理多个事件时,可以使用type属性:
<script type="text/javascript"> 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; </script>
则鼠标移动到按钮上时候,会显示红色.移开则恢复默认值.点击则弹出警告框.
我们可以通过preventDefault()来阻止特定事件的默认行为:
//阻止默认导航 var link = document.getElementById("myLink"); link.onclick = function(event) { event.preventDefault(); };
我们也可以使用stopPropagation()来停止事件在DOM层次中的传播:
<script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.onclick = function(event) { alert("Clicked"); event.stopPropagation(); //如果注释掉,则body会弹出警告框 }; document.body.onclick = function(event) { alert("Body clicked"); }; </script>
var EventUtil = { addHandler : function(element, type, handler) { //DOM2 if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent("on" + type, handler); } else { element["on" + 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) { //DOM2 if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } }, stopPropagation : function(event) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } } };
当页面完全加载后在window上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在<img>元素上面触发,或者当嵌入的内容加载完毕时在<object>元素上面触发.一般有两种指定onload事件处理程序的方式:第一种是JavaScript方式(推荐使用):
EventUtil.addHandler(window, "load", function(event){ alert("load window success!"); });第二种方式是在<body>元素添加一个onload特性(因为HTML中无法访问window元素):
<body onload="alert('load body success!')">而我们甚至可以在图像上触发load事件,具体实例如下:
<html> <script type="text/javascript" src="./print.js"></script> <script type="text/javascript" src="./EventUtil.js"></script> <!--body元素添加onload特性--> <body onload="alert('load body success!')"> <p>example for load event</p> <img id="myImage" src="smile.gif" onload="alert('load image success using HTML!')" /> <script type="text/javascript"> //整个页面加载成功后提示 EventUtil.addHandler(window, "load", function(event){ alert("load window success!"); }); //加载图像 var image = document.getElementById("myImage"); EventUtil.addHandler(image, "load", function(event){ event = EventUtil.getEvent(event); alert(EventUtil.getTarget(event).src); }); </script> </body></html>
界面依次弹窗显示:
load image success using HTML! file:///C:/Users/fzyz_sb/Desktop/smile.gif load body success! load window success!
但是,为什么下面的页面会卡住呢?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>example for load event</title> <script type="text/javascript" src="./EventUtil.js"></script> </head> <body onload="showBodyLoad()"> <img id="myImage" src="smile.gif" onload="showImageLoad()" /> <script type="text/javascript"> function print(str) { document.write(str + "<br />"); } function showBodyLoad() { print("show body load"); } function showImageLoad() { print("show image load"); } EventUtil.addHandler(window, "load", function(event){ print("load window success"); }); //加载图片 var image = document.getElementById("myImage"); EventUtil.addHandler(image, "load", function(event){ event = EventUtil.getEvent(event); print(EventUtil.getTarget(event).src); }); </script> </body></html>界面显示:
show image load后一直在加载.......
而我们可以为<script>和<link>指定事件处理程序:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>example for load event</title> <script type="text/javascript" src="./EventUtil.js"></script> </head> <body> <script type="text/javascript"> //为<script>元素指定事件处理程序 EventUtil.addHandler(window, "load", function(){ var script = document.createElement("script"); EventUtil.addHandler(script, "load", function(event){ alert("Loaded"); }); script.src = "print.js"; document.body.appendChild(script); }); //为<link>指定事件处理程序 EventUtil.addHandler(window, "load", function(){ var link = document.createElement("link"); link.type = "text/css"; link.rel = "stylesheet"; EventUtil.addHandler(link, "load", function(event){ alert("css loaded"); }); link.href = "style.css"; document.getElementsByTagName("head")[0].appendChild(link); }); </script> </body></html>界面一次弹出:
css loaded Loaded
当页面完全卸载后在window上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在<object>元素上面触发.
<script type="text/javascript"> EventUtil.addHandler(window, "unload", function(event){ alert("Unloaded"); }); </script>
但如何编写此实例呢?
当窗口或框架的大小变化时在window或框架上面触发.
<script type="text/javascript"> EventUtil.addHandler(window, "resize", function(event){ alert("resize window success!"); }); </script>
但是为什么resize会被触发两次呢?
当用户滚动带滚动条的元素中的内容时,在该元素上面触发.<body>元素中包含所加载页面的滚动条.
<script type="text/javascript"> EventUtil.addHandler(window, "scroll", function(event){ if (document.compatMode == "CSS1Compat") { alert(document.documentElement.scrollTop); } else { alert(document.body.scrollTop); } }); for (var i = 0; i < 100; i++) { print("hello world"); } </script>
与resize事件类似,scroll事件也会在文档被滚动期间重复触发,所以有必要尽量保持事件处理程序的代码简单.
焦点事件会在页面元素获得或失去焦点.有用的四个焦点事件:
1. blur:在元素失去焦点时触发.这个事件不会冒泡.
2. focus:在元素获得焦点时触发.这个事件不会冒泡.
3. focusin:在元素获得焦点时触发,与focus等价,但是冒泡.
4. focusout:在元素失去焦点时触发,与blur等价.
实例如下:
1. blur和focus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>example for load event</title> </head> <body> <input id="myBtn" type="button" value="click me" /> <script type="text/javascript"> var myBtn = document.getElementById("myBtn"); myBtn.addEventListener("focus", function(event){ alert("focus button"); }, false); myBtn.addEventListener("blur", function(event){ alert("blur button"); }, false); </script> </body></html>这里需要注意:blur会比focus先触发.如果一一测试(即测试focus时候屏蔽blur,测试blur时候屏蔽focus),则可以看到效果.
DOM3级事件定义了9个鼠标事件:
1. click:单击鼠标或按下回车键.
2. dblclick:双击主鼠标(一般是左鼠标)
3. mousedown:按下任意鼠标按钮
4. mouseenter:在鼠标光标从元素外部首次移动到元素范围内时触发.这个事件不冒泡.
5. mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发.这个事件不冒泡.
6. mousemove:当鼠标指针在元素内部移动时重复的触发.不能通过键盘触发这个事件.
7. mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发.
8. mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发.
9. mouseup:在用户释放鼠标按钮时触发.不能通过键盘触发这个事件.
鼠标事件都是在浏览器视口中的特定位置上发生的,这个位置信息保存在事件对象的clientX和clientY属性中,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标.
<div id="myDiv" style="background-color:red;height:100px;width:100px">Click me</div> <script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); alert("X:" + event.clientX + ",Y:" + event.clientY); }); </script>
当我们单击div内部时,会弹出坐标值:
而对于页面来说(存在滚轮的情况下),应该使用pageX和pageY.而对于整个屏幕而言,应该使用screenX和screenY:
<div id="myDiv" style="background-color:red;height:1000px;width:1000px">Click me</div> <script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); alert("X:" + event.clientX + ",Y:" + event.clientY); alert("PageX:" + event.pageX + ",PageY:" + event.pageY); alert("ScreenX:" + event.screenX + ",ScreenY:" + event.screenY); }); </script>
滚动鼠标到页面底部位置,单击即可看到坐标均不同.
我们可以通过shiftKey, ctrlKey,altKey和metaKey来判断Shift,Ctrl,Alt和Meta键是否被按下:
<div id="myDiv" style="background-color:red;height:1000px;width:1000px">Click me</div> <script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); var keys = new Array(); if (event.shiftKey) { keys.push("shift"); } if (event.ctrlKey) { keys.push("ctrl"); } if (event.altKey) { keys.push("alt"); } if (event.metaKey) { keys.push("meta"); } alert("Keys:" + keys.join(",")); }); </script>
而浏览器响应如下:
对于mouseover和mouseout事件而言,会设计更多的元素.对mouseover事件而言,事件的主目标是获得光标的元素,而相关元素就是那个失去光标的元素.类似的,对于mouseout事件而言,事件的主目标是失去光标的元素,而相关元素则是获得光标的元素.
<div id="myDiv" style="background-color:red;height:100px;width:100px">Click me</div>
在页面上会显示一个<div>元素.如果鼠标指针一开始位于这个<div>元素上,然后移出了这个元素,那么就会在<div>元素上触发mouseout事件,相关元素就是<body>元素.与此同时,<body>元素上面会触发mouseover事件,而相关元素变成了<div>.
我们可以通过属性relatedTarget来获取元素的信息:
<script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "mouseout", function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); var relatedTarget = EventUtil.getRelatedTarget(event); alert("moused out of " + target.tagName + " to " + relatedTarget.tagName); }); </script>
有三个键盘事件:
1. keydown:按下键盘上面的任意键时候触发,如果按住不放会重复触发.
2. keypress:按下键盘上的字符键时触发,如果按下不放会重复触发.
3. keyup:释放键盘上的键时触发.
一个文本事件:textInput.在文本插入文本框之前会触发textInput事件.
1. 键码:当发生keydown时,event对象的keyCode属性会包含一个代码,与特定的键对应.
2. 字符编码:为charCode
但是一般情况下,keyCode和charCode不可同时拥有值,所以会做出如下的判断:
getCharCode: function(event){ if (typeof event.charCode == "number"){ return event.charCode; } else { return event.keyCode; } },
实例如下:
<input id="myText" type="text" value="input" /> <script type="text/javascript"> function print(str) { document.write(str + "<br />"); } var myText = document.getElementById("myText"); EventUtil.addHandler(myText, "keyup", function(event){ event = EventUtil.getEvent(event); alert(event.keyCode); }); </script>每次输入字符,会弹出其ASCII码.
而DOM3级事件引入了一个新事件:textInput.它和keypress的textInput事件的行为不同在于两点:
1. 任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发textInput事件.
2. textInput事件只会在用户按下能够输入实际字符的键时才会被触发,而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)
var myText = document.getElementById("myText"); EventUtil.addHandler(myText, "textInput", function(event){ event = EventUtil.getEvent(event); alert(event.data); });备注:firefox不支持此事件(貌似还没有浏览器支持它).
变动事件是为XML或HTML DOM设计的:
1. DOMSubtreeModified:在DOM结构中发生任何变化时触发.这个事件在其他任何事件触发后都会触发.
2. DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中触发.
3. DOMNodeRemoved:在节点从其父节点中被移除时触发.
4. DOMNodeInsertedIntoDocument:在一个节点被直接插入文档或通过子树间接插入文档之后触发.这个事件在DOMNodeInserted之后触发.
5. DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发.这个事件在DOMNodeRemoved之后触发.
6. DOMAttrModified:在特性被修改之后触发.
7. DOMCharacterDataModified:在文本节点的值发生变化时触发.
以以下HTML页面为例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Node Removal Events Example</title> <script type="text/javascript" src="./EventUtil.js"></script> </head> <body> <ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> </body> <script type="text/javascript"> function print(str) { document.write(str + "<br />"); } EventUtil.addHandler(window, "load", function(event){ var list = document.getElementById("myList"); EventUtil.addHandler(document, "DOMSubtreeModified", function(event){ print("---DOMSubtreeModified"); print(event.type); print(event.target); }); EventUtil.addHandler(document, "DOMNodeRemoved", function(event){ print("---DOMNodeRemoved"); print(event.type); print(event.target); print(event.relatedNode); }); EventUtil.addHandler(document, "DOMNodeRemovedFromDocument", function(event){ print("---DOMNodeRemovedFromDocument"); print(event.type); print(event.target); }); list.parentNode.removeChild(list); }); </script> </html>要移除<ul>元素,会依次触发以下事件:
1. 在<ul>元素上触发DOMNodeRemoved事件.relatedNode属性等于document.body.
2. 在<ul>元素上触发DOMNodeRemovedFromDocument事件.
3. 在身为<ul>元素子节点的每个<li>元素及文本节点上触发DOMNodeRemovedFromDocument事件.
4. 在document.body上触发DOMSubtreeModefied事件,因为<ul>元素是document.body的直接子元素.
可以,界面上就触发了DOMNodeRemoved事件,这到底是为什么?
浏览器显示如下:
---DOMNodeRemoved DOMNodeRemoved [object HTMLUListElement] [object HTMLBodyElement]
与上面类似:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Node Removal Events Example</title> <script type="text/javascript" src="./EventUtil.js"></script> <script type="text/javascript"> function print(str) { document.write(str + "<br />"); } EventUtil.addHandler(window, "load", function(event){ var list = document.getElementById("myList"); var item = document.createElement("li"); item.appendChild(document.createTextNode("Item 4")); EventUtil.addHandler(document, "DOMSubtreeModified", function(event){ alert("---DOMSubtreeModified"); alert(event.type); alert(event.target); }); EventUtil.addHandler(document, "DOMNodeInserted", function(event){ alert("---DOMNodeRemoved"); alert(event.type); alert(event.target); alert(event.relatedNode); }); EventUtil.addHandler(document, "DOMNodeInsertedIntoDocument", function(event){ alert("---DOMNodeRemovedFromDocument"); alert(event.type); alert(event.target); }); list.parentNode.removeChild(list); }); </script> </head> <body> <ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> </body> </html>
上下文菜单事件:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>ContextMenu Event Example</title> <script type="text/javascript" src="./EventUtil.js"></script> <script type="text/javascript"> EventUtil.addHandler(window, "load", function(event){ var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "contextmenu", function(event){ event = EventUtil.getEvent(event); EventUtil.preventDefault(event); var menu = document.getElementById("myMenu"); menu.style.left = event.clientX + "px"; menu.style.top = event.clientY + "px"; menu.style.visibility = "visible"; }); EventUtil.addHandler(document, "click", function(event){ document.getElementById("myMenu").style.visibility = "hidden"; }); }); </script> </head> <body> <div id="myDiv">click me</div> <ul id="myMenu" style="position: absolute;visibility: hidden;background-color: silver"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> </body> </html>
为了让开发人员有可能在页面卸载前阻止这一操作而定义了beforeunload,当然,这个事件是通知用户界面将被卸载(但是具体如何举例依旧不知道):
EventUtil.addHandler(window, "beforeunload", function(event){ event = EventUtil.getEvent(event); var message = "really goodbye!"; event.returnValue = message; return message; });
此事件则在形成完整的DOM树之后会被触发.
var EventUtil = { 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; } }, getButton: function(event){ if (document.implementation.hasFeature("MouseEvents", "2.0")){ return event.button; } else { switch(event.button){ case 0: case 1: case 3: case 5: case 7: return 0; case 2: case 6: return 2; case 4: return 1; } } }, getCharCode: function(event){ if (typeof event.charCode == "number"){ return event.charCode; } else { return event.keyCode; } }, getClipboardText: function(event){ var clipboardData = (event.clipboardData || window.clipboardData); return clipboardData.getData("text"); }, getEvent: function(event){ return event ? event : window.event; }, getRelatedTarget: function(event){ if (event.relatedTarget){ return event.relatedTarget; } else if (event.toElement){ return event.toElement; } else if (event.fromElement){ return event.fromElement; } else { return null; } }, getTarget: function(event){ return event.target || event.srcElement; }, getWheelDelta: function(event){ if (event.wheelDelta){ return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); } else { return -event.detail * 40; } }, 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; } }, setClipboardText: function(event, value){ if (event.clipboardData){ event.clipboardData.setData("text/plain", value); } else if (window.clipboardData){ window.clipboardData.setData("text", value); } }, stopPropagation: function(event){ if (event.stopPropagation){ event.stopPropagation(); } else { event.cancelBubble = true; } } };