说说 JavaScript 事件流之事件类型(包含 DOM2、DOM3 级事件)
来源:互联网 发布:笔记本usb端口上的电涌 编辑:程序博客网 时间:2024/05/21 11:01
DOM3 级事件规定了这些事件:
1 UI 事件
DOM 规范为了保证向后兼容,已经保留了 UI 事件。有这些 UI 事件:
<img>
上触发,当嵌入内容加载完毕时在 <object>
元素上触发。 unload 在页面完全卸载时在 window 上触发,当所有框架都卸载完毕时在框架集上触发,当嵌入内容卸载完毕时在 <object>
元素上触发。 abort 用户停止了下载,这是如果嵌入的内容还未加载完,就在 <object>
元素上触发。 error 发生 JavaScript 错误时在 window 上触发,当无法加载图像时在 <img>
上触发,当无法加载嵌入内容时在 <object>
元素上触发,当有一个或多个框架无法加载时在框架集上触发。 select 当用户选择 <input>
或 <textarea>
中的一个或多个字符时触发。 resize 当窗口或框架的大小发生变化时在 window 或框架上触发。 scroll 当用户滚动带有滚动条的元素中的内容时,在该元素上触发。多数事件都与 window 对象或者表单控件有关。
除了 DOMActivate 外,其他事件在 DOM2 级事件中都归为 HTML 事件,这样确定浏览器是否支持 DOM2 级事件规定的 HTML 事件:
var isSupported = document.implementation.hasFeature("HTMLEvents","2.0");
这样确定浏览器是否支持 DOM3 级事件规定的 UI 事件:
var isSupported = document.implementation.hasFeature("UIEvent","3.0");
1.1 load 事件
当页面完全加载时就会触发 window 上的 load 事件。有两种定义 onload 事件的方法。第一种是通过 JavaScript 来指定的:
<script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> EventUtil.addHandler(window, "load", function (event) { console.log("Loaded!"); });</script>
EventUtil.js 请参见 这里
第二种是在 <body>
元素中添加一个 onload 属性:
<body onload="console.log('Loaded!')"></body>
建议尽量使用 JavaScript 的方式来指定!
注意: DOM2 级事件规范要求在 document 上触发 load 事件。但所有的浏览器为了确保向后兼容,都在 window 上实现了这一事件!
也可以为图像指定 onload 事件:
<img src="http://avatar.csdn.net/D/4/8/1_deniro_li.jpg" onload="console.log('Image loaded.')">
上面的例子也可以用 JavaScript 来实现:
<img id="myImage" src="http://avatar.csdn.net/D/4/8/1_deniro_li.jpg" ><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> var image = document.getElementById("myImage"); EventUtil.addHandler(image, "load", function (event) { event = EventUtil.getEvent(event); console.log(EventUtil.getTarget(event).src); });</script>
创建新的 <img>
元素时,可以为其指定一个事件,但必须在指定 src 属性之前先指定事件,这样才能在图像加载完毕时给出提示:
<script type="text/javascript"> EventUtil.addHandler(window, "load", function (event) { var image = document.createElement("img"); EventUtil.addHandler(image, "load", function (event) {//先指定事件 event = EventUtil.getEvent(event); console.log(EventUtil.getTarget(event).src); }); document.body.appendChild(image); image.src = "http://avatar.csdn.net/D/4/8/1_deniro_li.jpg";//再指定 src });</script>
注意,新的图像元素只要设置了 src 属性就会开始下载!
通过的功能也可以使用 DOM0 级的 Image 对象来实现。在 DOM 出现之前,开发人员经常使用 Image 对象为客户端预加载图像,只不过 Image 对象无法添加到 DOM 树中:
<script type="text/javascript"> EventUtil.addHandler(window, "load", function (event) { var image = new Image(); EventUtil.addHandler(image, "load", function (event) {//先指定事件 console.log("Image loaded!"); }); image.src = "http://avatar.csdn.net/D/4/8/1_deniro_li.jpg";//再指定 src });</script>
注意: 在不属于 DOM 文档的图像(未添加到文档的 <img>
元素和 Image 对象)上触发 load 事件时,IE8 及之前的版本是不会生成 event 对象的!IE9 修复了这个问题。
还有一些元素以非标准的方式支持 load 事件。IE9+、Firefox、Opera、Chrome 和 Safari 3+ 及更高版本中,<script>
元素也会触发 load 事件,这样做可以方便开发人员确定动态加载的 JavaScript 文件是否已经加载完毕。只有设置了 <script>
元素的 src 属性并将该元素添加到文档后,才会开始下载 JavaScript 文件:
EventUtil.addHandler(window, "load", function (event) { var script = document.createElement("script"); EventUtil.addHandler(script, "load", function (event) { console.log("Loaded"); }); script.src = "http://c.csdnimg.cn/pubfooter/js/tracking.js"; document.body.appendChild(script);
IE、Chrome 和 Opera 还支持在 <link>
元素上的 load 事件,以便开发人员确定样式表是否已经加载完毕:
//动态添加样式表var link = document.createElement("link");link.type = "text/css";link.rel = "stylesheet";EventUtil.addHandler(link, "load", function (event) { console.log("css loaded");});link.href = "http://c.csdnimg.cn/public/common/toolbar/css/index.css"document.getElementsByTagName("head")[0].appendChild(link);
只有指定了 href 属性并且添加到文档中的 <link>
元素才会开始下载样式表。
1.2 unload 事件
当文档被完全卸载后就会触发。用户从一个页面切换到另一个页面,也会发生 unload 事件。一般利用这个事件来清除引用,避免内存泄漏。也有两种指定 unload 事件的方法,第一种是使用 JavaScript 来指定:
EventUtil.addHandler(window, "unload", function(event){ console.log("Unloaded");});
此时的 event 对象在兼容 DOM 的浏览器中只有 target 属性(值为 document)。IE8 及之前的版本则为这个对象提供了 srcElement 属性。
第二种方式是,为 <body>
元素添加 onunload 属性:
<body onunload="alert('Unloaded!')"></body>
注意: 根据 DOM2 级事件的规范,应该在 <body>
元素上触发 unload 事件。但所有的浏览器为了确保向后兼容,都在 window 上实现了 unload 事件。
1.3 resize 事件
当浏览器窗口的宽高发生变化时,就会触发 resize 事件。它会在 window 上触发,可以通过 JavaScript 或 <body>
元素中的 onresize 属性来指定,还是推荐使用 JavaScript 来指定:
EventUtil.addHandler(window, "resize", function(event){ console.log("Resized");});
此时的 event 对象在兼容 DOM 的浏览器中只有 target 属性(值为 document)。IE8 及之前的版本没有提供任何属性!
何时会触发 resize 事件,不同的浏览器有不同的机制。IE、Safari、Chrome 和 Opera 会在浏览器窗口变化了 1 个像素时,触发 resize 事件,然后随着变化不断重复触发。Firefox 只会在用户停止调整窗口大小时,才会触发 resize 事件。这个事件可能会被频繁地执行,因此不要在 resize 事件中加入具有大计算量的代码,这会导致浏览器的反应明显变慢。
注意: 最大化或最小化浏览器窗口,都会触发 resize 事件。
1.4 scroll 事件
虽然 scroll 事件是在 window 对象上触发的,但它实际表示的是页面中相应的元素发生了变化。在混杂模式下,可以通过 <body>
元素的 scrollLeft 和 scrollTop 来监控这一变化;在标准模式下,除了 Safari 之外的所有浏览器都会通过 <html>
元素来监控这一变化(Safari 中仍是基于 <body>
元素来监控的):
<script type="text/javascript"> EventUtil.addHandler(window, "scroll", function (event) { if (document.compatMode == "CSS1Compat") { console.log(document.documentElement.scrollTop); } else { console.log(document.body.scrollTop); } });</script>
与 resize 事件类似, scroll 事件也会在文档滚动期间被重复地触发,所以要保持 scroll 事件足够简单!
2 焦点事件
焦点事件会在页面获得或者失去焦点时触发。利用焦点事件并与 document.hasFocus() 方法以及 document.activeElement 属性相配合,可以获知用户在页面上的行踪,有这些焦点事件:
focus 和 blur 最大的问题是不冒泡,所以 IE 的 focusin 和 focusout 才被 DOM3 级事件采纳为标准。
当焦点从页面中的一个元素移动到另一个元素时,会依次触发这些事件:
1. focusout 在失去焦点的元素上触发。
2. focusin 在获得焦点的元素上触发。
3. blur 在失去焦点的元素上触发。
4. DOMFocusOut 在失去焦点的元素上触发。
5. focus 在获得焦点的元素上触发。
6. DOMFocusIn 在获得焦点的元素上触发。
使用以下代码可以确定浏览器是否支持这些事件:
var isSupported = document.implementation.hasFeature("FocusEvent","3.0");
3 鼠标和滚轮事件
DOM3 级事件定义了 9 个鼠标事件:
页面上的所有元素都支持鼠标事件。除了 mousedown 和 mouseup 之外,其他所有鼠标事件都会冒泡,它也可以被取消。
只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果 mousedown 和 mouseup 事件有一个被取消,那么就不会触发 click 事件。只有触发两次 click 事件,才会触发一次 dblclick 事件。它们的触发顺序是这样的:
1. mousedown
2. mouseup
3. click
4. mousedown
5. mouseup
6. click
7. dblclick
click 和 dblclick 事件会依赖于其他先行事件。
IE8 及之前的版本有一个 bug,就是在双击事件中,会跳过第二个 mousedown 和 click 事件。IE9 修复了这一 bug。
使用以下代码可以确定浏览器是否支持这些 DOM2 事件(除 dbclick、mouseenter 和 mouseleave 之外):
var isSupported = document.implementation.hasFeature("MouseEvents","2.0");
使用以下代码可以确定浏览器是否支持这些 DOM3 事件:
var isSupported = document.implementation.hasFeature("MouseEvent","3.0");
注意:这里是 “MouseEvent”!
还有一个 mousewheel 事件,它会跟踪鼠标的滚轮。
3.1 客户区坐标位置
鼠标事件都是在浏览器视口的特定位置上发生的。这些位置信息保存在事件对象的 clientX 和 clientY 中。所有浏览器都支持这两个属性,它们表示事件发生时鼠标指针在视口中的水平和垂直坐标:
<div id="myDiv">点我</div><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function (event) { event = EventUtil.getEvent(event); console.log("Client coordinates:" + event.clientX + "," + event.clientY); })</script>
因为这些值不表示鼠标在页面上的位置,所以它们并不包含页面的滚动距离。
3.2 页面坐标位置
通过事件对象的 pageX 和 pageY 属性,可以获得事件是在页面中什么位置发生的,即鼠标光标在页面中的位置,因为坐标是从页面本身的左边和顶边计算得出的:
<div id="myDiv">点我</div><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function (event) { event = EventUtil.getEvent(event); console.log("Page coordinates:" + event.pageX + "," + event.pageY); })</script>
页面没有滚动的情况下,pageX 等于 clientX,pageY 等于 clientY。
IE8 及早期版本不支持事件对象上的页面坐标,但可以通过客户区坐标和滚动信息计算出来。这需要用到 document.body(混杂)或 document.documentElement(标准)中的 scrollLeft 和 scrollTop 属性:
<script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function (event) { event = EventUtil.getEvent(event); var pageX = event.pageX; var pageY = event.pageY; if (pageX === undefined) { pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft); } if (pageY === undefined) { pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop); } console.log("Page coordinates:" + pageX + "," + pageY); })</script>
3.3 屏幕坐标位置
这是鼠标事件发生时,相对于整个电脑屏幕的位置:
<script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function (event) { event = EventUtil.getEvent(event); console.log("Screen coordinates:" + event.screenX + "," + event.screenY); })</script>
3.4 修改键
配合这些修改键——Shift、Ctrl、Alt 和 Meta(Windows 中是 Windows 键,苹果中是 Cmd 键),经常被用来修改鼠标事件的行为。DOM 规定了 shiftKey、ctrlKey、altKey、metaKey,它们都是布尔值,如果相应的键被按下,它的值变为 true。当某个鼠标事件发生时,通过检测这些属性就能确定用户是否同时按下了其中的键:
<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"); } console.log("Keys:" + keys.join(",")); })</script>
注意: IE9、Firefox、Safari、Chrome 和 Opera 都支持这 4 个键。IE8 及之前的版本不支持 metaKey 属性。
3.5 相关元素
发生 mouseover 和 mouseout 事件时,会涉及到其他元素。mouseover 事件中,主目标是获得光标的元素,相关元素是失去光标的元素;mouseout 事件,主目标是失去光标的元素,相关元素是获得光标的元素。
在 EventUtil.js 中添加:
/** * 获取相关元素 * @param event * @returns {*} */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; }}
这样使用:
<div id="myDiv" style="background-color: red;height:100px;width: 100px;"></div><script type="text/javascript" src="EventUtil.js"></script><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); console.log("Moused out of " + target.tagName + " to " + relatedTarget.tagName); });</script>
3.6 鼠标按钮
DOM 的 button 属性有这些值:
IE8 及之前的版本也提供了 button 属性,但有 8 种值!所以 DOM 模型定义的更简明实用。我们把 IE 的选项转换为 DOM 模型的选项,就可以实现跨浏览器获取 button 属性值:
/** * 获取鼠标点击事件类型 * 0:主鼠标按钮;1:中间鼠标按钮;2:次鼠标按钮 * @param event * @returns {*} */getButton: function (event) { if (document.implementation.hasFeature("MouseEvents", "2.0")) {//支持 DOM 版的鼠标事件 return event.button; } else { switch (event.button) {//IE8 及早期版本 case 0: case 1: case 3: case 5: case 7: return 0; case 2: case 6: return 2; case 4: return 1; } }}
这样使用:
<script type="text/javascript"> var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "mousedown", function (event) { event = EventUtil.getEvent(event); console.log(EventUtil.getButton(event)); })</script>
注意: 使用 onmouseup 事件处理程序时,button 的值表示释放的是哪个鼠标按钮。在 Opera 中,只有按下或释放了主鼠标按钮,才会触发 mouseup 或 mousedown 事件。
3.7 更多的事件信息
DOM2 级事件规范中,event 对象还有一个 detail 属性。对于鼠标事件来说,detail 表示给定位置上发生了多少次单击。在同一个像素上相继发生一次 mousedown 和一次 mouseup 事件总算一次单击。它从 1 开始计数,每次单击后会递增。如果鼠标在 mousedown 和 mouseup 之间移动了位置,detail 会被重置为 0。
IE 也通过其他属性为鼠标事件提供了更多信息。但只有 IE 支持它们,所以没什么用处,这里也就不列举咯 O(∩_∩)O~
3.8 鼠标滚轮事件
当用户通过鼠标滚轮与页面交互(在垂直方向上滚动页面时),会触发 mousewheel 事件。它可以在任何元素上触发,最终会冒泡到 document(IE8)或 window (IE9、Opera、Chrome 及 Safari)对象。mousewheel 事件还包含 wheelDelta 属性,当向前滚动鼠标滚轮时,wheelDelta 是 120 的倍数;当向后滚动鼠标滚轮时,wheelDelta 是 -120 的倍数:
将 mousewheel 的事件处理程序指定给页面中的任何元素,或者 document 对象,就可处理鼠标滚轮的交互操作。多数情况下,只需要知道鼠标滚轮的滚动方向。在 Opera 9.5 之前的版本,wheelDelta 的正负值是颠倒的:
<script type="text/javascript" src="ClientUtil.js"></script><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> EventUtil.addHandler(document, "mousewheel", function (event) { event = EventUtil.getEvent(event); var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);//opera 9.5 之前的版本,wheelDelta 正负号是颠倒的 console.log(delta); })</script>
ClientUtil.js 请参见这里。
注意: HTML 5 也加入了 mousewheel 事件。
Firefox 支持 DOMMouseScroll 事件,会在鼠标滚轮滚动时触发。滚轮的信息保存在 detail 属性中,当向前滚动时,它是 -3 的倍数,当向后滚动时,它是 3 的倍数:
DOMMouseScroll 可以添加到页面中的任何元素,它会冒泡到 window 对象。
因此,跨浏览器的方案是:
/** * 获取鼠标滚动的滚动值 * @param event * @returns {number} */getWheelDelta: function (event) { if (event.wheelDelta) { return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); } else {//Firefox return -event.detail * 40; }}
这样使用:
<script type="text/javascript"> (function () { function handleMouseWheel(event) { event = EventUtil.getEvent(event); var delta = EventUtil.getWheelDelta(event); console.log(delta); } EventUtil.addHandler(document, "mousewheel", handleMouseWheel); EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel); })();</script>
我们把代码放在一个私有的作用域中,这样就不会让新定义的函数干扰到全局作用域。这里把 handleMouseWheel() 作为两个事件的处理程序,如果指定的事件不存在,那么代码会静默地失败。
4 键盘与文本事件
对键盘事件的支持,遵循的是 DOM0 级规范。有这些事件:
所有元素都支持,但一般在文本框中常用到这些事件。
textInput 是文本事件,会在文本插入文本框之前触发,用于在将文本展示给用户时拦截文本。
用户按了下键盘上的字符键时,会先触发 keydown 事件,然后是 keypress 事件,最后是 keyup 事件。keydown 和 keypress 都是在文本框发生变化之前被触发,keyup 是在文本框发生变化之后触发。如果按下一个键不放,会重复触发 keydown 和 keypress 事件。
如果按下的是非字符键, 会先触发 keydown 事件,然后是 keyup 事件。。如果按下一个键不放,会重复触发 keydown 事件。
注意: 键盘事件与鼠标事件一样,也支持修改键(shiftKey、ctrlKey、altKey 和 metaKey)。IE 不支持 metaKey。
4.1 键码
发生 keydown 和 keyup 事件时,event 对象的 keyCode 属性会有一个键码,它与键盘上的一个特定值相对应。对于数字字母键,keyCode 属性会包含一个代码,它与键盘上的一个特定键相对应。DOM 和 IE 的 event 对象都支持 keyCode 属性:
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "keyup", function (event) { event = EventUtil.getEvent(event); console.log(event.keyCode); });</script>
下面是所有非字符键的键码:
4.2 字符编码
所有的浏览器中,按下能插入或者删除字符的键都会触发 keypress 事件。
IE9、Firefox、Chrome 和 Safari 的 event 对象都支持 charCode 属性,会触发 keypress 事件时,charCode 属性才包含值,表示的是按下的键对代表字符的 ASCII 编码。IE8 及之前的版本和 Opera 支持的是类似功能的 charCode。以下的跨浏览器的代码:
/** * 取得键盘按下的字符编码 * @param event * @returns {*} */getCharCode: function (event) { if (typeof event.charCode == "number") { return event.charCode; } else { return event.keyCode; }}
这样使用:
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "keypress", function (event) { event = EventUtil.getEvent(event); var charCode = EventUtil.getCharCode(event); console.log(charCode); console.log(String.fromCharCode(charCode));//转为实际字符 });</script>
4.3 DOM3 级变化
4.3.1 key 和 char 属性
DOM3 级中的键盘事件包含 key 和 char。
key 是字符串。按下某个字符键,值是对应的文本字符;按下非字符键,值是对应的键名。char 在按下字符键时,值与 key 相同;按下非字符键时,值为 null。
IE9 支持 key 属性,但不支持 char 属性。Safari 5 和 Chrome 支持 keyIdentifier 属性,它在按下非字符键时,与 key 相同:
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "keypress", function (event) { event = EventUtil.getEvent(event); var identifier=event.key||event.keyIdentifier; if(identifier){ console.log(identifier); } });</script>
注意: 因为跨浏览器的问题,所以目前暂时不建议使用 key、keyIdentifier 或 char。
4.3.2 location 属性
它表示在什么位置按下了键:
IE9 支持。Safari 和 Chrome 支持 keyLocation 的等价属性,但只有两个值!3 表示数字小键盘,0表示其它情况:
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "keypress", function (event) { event = EventUtil.getEvent(event); var loc = event.location || event.keyLocation; if (loc) { console.log(loc); } });</script>
因为支持这一属性的浏览器不多,所以建议在跨浏览器方案中不要使用!
4.3.3 getModifierState() 方法
它接受一个参数,表示要检测的修改键(Shift、Control、AltGraph 或 Meta 字符串)。如果指定的修改键被按下,这个方法会返回 true:
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "keypress", function (event) { event = EventUtil.getEvent(event); if (event.getModifierState) { console.log(event.getModifierState("Shift"));//chrome 与 IE10 也支持 } });</script>
4.4 textInput 事件
textInput 事件与 keypress 事件的区别:
textInput 事件的 event 对象还包含 data 属性,它表示的是用户输入的字符(不是字符编码!),比如按下了 A 键,就是 “a”,如果按住上档键的情况下按下了该键,就是 “A”。
<script type="text/javascript"> var textbox = document.getElementById("myText"); EventUtil.addHandler(textbox, "textInput", function (event) { event = EventUtil.getEvent(event); console.log(event.data); });</script>
event 对象上还有一个 inputMethod 属性,表示把文本输入到文本框中方式:
使用这个属性得到文本输入控件的方式,从而验证文本的有效性。支持 textInput 属性的浏览器有 IE9+、Safari 和 Chrome。。只有 IE 支持 inputMethod 属性。
5 变动事件
DOM2 级定义的变动事件会监听 DOM 中的某一部分发生的变化。有这些事件:
可以使用下列代码来检测浏览器是否支持变动事件:
var isSupported=document.implementation.hasFeature("MutationEvents","2.0");
下列列出不同浏览器对这些变动事件的支持情况:
5.1 删除节点
使用 removeChild() 或 replaceChild() 从 DOM 中删除节点时,会触发 DOMNodeRemoved 事件。它的 event.target 是被删除的节点,event.relatedNode 是目标节点父节点的引用。这个事件被触发时,节点尚未从其父节点被删除,所以它的 parentNode 仍然指向父节点。这个事件会冒泡,所以可以在 DOM 的任何层次处理它。
如果被移除的节点包含子节点,那么它所有的子节点以及这个节点会相继触发 DOMNodeRemovedFromDocument 事件。但它不会冒泡,所以只有直接指定给其中一个子节点的事件处理程序才会调用这个事件。这个事件的 event.target 是相应的子节点或者那个被移除的节点。
最后触发 DOMSubtreeModified 事件。这个事件的 event.target 是被移除节点的父节点。
<body><ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li></ul><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> 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) { console.log(event.type); console.log(event.target); }); EventUtil.addHandler(document, "DOMNodeInserted", function (event) { console.log(event.type); console.log(event.target); console.log(event.relatedNode); }); EventUtil.addHandler(item, "DOMNodeInsertedIntoDocument", function (event) { console.log(event.type); console.log(event.target); }); list.appendChild(item); })</script></body>
5.2 插入节点
使用 appendChild()、replaceChild() 或 insertBefore() 向 DOM 插入节点时,会先触发 DOMNodeInserted 事件。这个事件的 event.target 是被插入的节点,event.relatedNode 是父节点的引用。这个事件触发时,节点已被插入到父节点中。它是冒泡的,所有可以在 DOM 的各个层次处理它。
接着会在新插入的节点上触发 DOMNodeInsertedIntoDocument 事件。它不会冒泡,所以必须在插入节点之前为它添加事件处理程序。这个事件的 event.target 是被插入的节点。
最后一个触发 DOMSubtreeModified 事件。
<body><ul id="myList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li></ul><script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> EventUtil.addHandler(window, "load", function (event) { var list = document.getElementById("myList"); EventUtil.addHandler(document, "DOMSubtreeModified", function (event) { console.log(event.type); console.log(event.target); }); EventUtil.addHandler(document, "DOMNodeRemoved", function (event) { console.log(event.type); console.log(event.target); console.log(event.relatedNode); }); EventUtil.addHandler(list.firstChild, "DOMNodeRemovedFromDocument", function (event) { console.log(event.type); console.log(event.target); }); list.parentNode.removeChild(list); })</script></body>
6 HTML5 事件
HTML5 详细地列出了浏览器应该支持的所有事件,我们只说说那些得到浏览器支持的事件。
6.1 contextmenu 事件
它用于表示何时显示上下文菜单(即鼠标右击菜单),以便开发人员可以取消默认的上下文菜单而提供自定义的菜单。
因为这个事件是冒泡的,所以可以在 document 指定一个事件处理程序。它的 event.target 是发生用户操作的元素。所有的浏览器都可以取消这个事件:兼容的 DOM 的浏览器中,是使用 event.preventDefault();IE 中,是将 event。returnValue 的值设为 false。因为 contextmenu 事件是鼠标事件,所以它的事件对象包含于光标位置有关的属性。通常使用 contextmenu 事件来显示自定义的上下文菜单,使用 onclick 事件来隐藏这个菜单:
<div id="myDiv">Right click or Ctrl+click me to get a custom context menu. Click anywhere else to get the default context menu.</div><ul id="myMenu" style="position: absolute;visibility: hidden;background-color: silver"> <li><a href="http://www.163.com">163 site</a></li> <li><a href="http://www.baidu.com">baidu site</a></li></ul><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>
效果如下:
在这个例子中为菜单加一些 CSS 样式,就可以得到很好的效果!
这些浏览器支持 contextmenu 事件:IE、Firefox、Safari、Chrome 和 Opera 11+。
6.2 beforeunload 事件
这个事件是为了让开发人员可以在页面卸载时,可以出现提示,让用户选择是否真的要关闭这个页面,还是继续留下来:
可以将 event.returnValue 的值设置为要显示给用户的字符串:
<script type="text/javascript" src="EventUtil.js"></script><script type="text/javascript"> EventUtil.addHandler(window, "beforeunload", function (event) { event = EventUtil.getEvent(event); var message = "I'm really going to miss you if you go."; event.returnValue = message; return message; })</script>
IE、Firefox、Safari、Chrome 都支持 beforeunload 事件,但 Opera 11 及之前的版本不支持!
6.3 DOMContentLoaded 事件
这个事件会在形成完整的 DOM 树之后触发,而 load 事件必须在页面中的所有资源都加载完毕才会触发。 所以利用 DOMContentLoaded 事件,可以让用户尽可能早地与页面进行交互。
可以为 document(实际目标)或 window(冒泡过来的) 添加相应的事件处理程序:
<script type="text/javascript"> EventUtil.addHandler(document, "DOMContentLoaded", function (event) { console.log("Content loaded"); })</script>
这个事件的对象没有听过任何额外的信息!
这些浏览器支持 DOMContentLoaded 事件:IE9+、Firefox、Safari 3.1+、Chrome 和 Opera 9+。这个事件始终都会在 load 事件之前触发。
对于不支持 DOMContentLoaded 事件的浏览器,建议在页面加载期间设置一个时间为 0 毫秒的超时调用:
setTimeout(function(){ //添加事件处理程序},0);
这段脚本应该会在页面下载和构建期间被触发。为了确保这个方法有效,必须将它作为页面的第一个超时调用,但无法完全保证它一定早于 load 事件被触发!
6.4 readystatechange 事件
它会提供与文档或元素的加载状态有关的信息。支持 readystatechange 事件的对象都有一个 readyState 属性,它可能包含这些值:
属性值(阶段) | 说明
uninitialized | 对象存在但还未初始化。
loading | 对象正在加载数据。
loaded | 加载数据完成。
interacdtive | 可以操作对象。
complete | 对象已加载完毕。
注意,并非所有对象都会经历上述的这些阶段!而且无法保证顺序!所以,有必要同时检测交互和完成阶段:
<script type="text/javascript"> EventUtil.addHandler(document, "readystatechange", function (event) { if (document.readyState == "interactive" || document.readyState == "complete") { EventUtil.removeHandler(document, "readystatechange", arguments.callee); console.log("Content loaded"); } });</script>
因为使用了匿名函数作为事件处理程序,所以使用了 arguments.callee 来引用这个函数。
IE、Firefox 4+ 和 Opera 支持 readystatechange 事件。
注意: readystatechange 与 DOMContentLoaded 事件在本上的是不同的。而且,load 事件和 readystatechange 事件都不能保证以相同的顺序触发。
<script>
(IE 和 Opera)和 <link>
(仅 IE )也会触发 readystatechange 事件,它可以确定外部的 JavaScript 和 CSS 文件是否已经加载完成。但这个事件也跟元素触发的 readystatechange 事件一样存在问题,所以也需要同时检测:
<script type="text/javascript"> EventUtil.addHandler(window, "load", function () { var script = document.createElement("script"); EventUtil.addHandler(script, "readystatechange", function (event) { event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //防止被执行两次,所以移除这个事件处理程序 if (document.readyState == "loaded" || document.readyState == "complete") { EventUtil.removeHandler(target, "readystatechange", arguments.callee); console.log("Script loaded"); } }); script.src = "http://static.blog.csdn.net/scripts/jquery.js"; document.body.appendChild(script); });</script>
下面是针对 <link>
元素加载 CSS 文件的情况:
<script type="text/javascript"> EventUtil.addHandler(window, "load", function () { var link = document.createElement("link"); link.type = "text/css"; link.rel = "stylesheet"; EventUtil.addHandler(link, "readystatechange", function (event) { event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); if (document.readyState == "loaded" || document.readyState == "complete") { EventUtil.removeHandler(target, "readystatechange", arguments.callee); console.log("CSS loaded"); } }); link.href = "http://c.csdnimg.cn/public/common/toolbar/css/index.css"; document.getElementsByTagName("head")[0].appendChild(link); document.body.appendChild(link); });</script>
这里同时检测了 readyState 的两个状态,并在调用过一次事件处理程序之后,就将其移除咯。
6.5 hashchange 事件
它会在 URL(# 后面的所有字符串) 的参数列表发生变化时触发。
要把这个事件添加给 window 对象。它的 event 对象包含 oldURL 和 newURL,即参数变化前后的完整的 URL:
<script type="text/javascript"> EventUtil.addHandler(window, "haschange", function (event) { console.log("Old URL: " + event.oldURL + "\nNew URL:" + event.newURL); console.log("Current hash:" + location.hash); })</script>
IE8+、Firefox 3.6+、Safari 5+、Chrome 和 Opera 10.6+ 都支持这个事件,但只有 Firefox 6+、Chrome 和 Opera 支持 oldURL 和 newURL,所以最好使用 location 对象来确定当前的参数列表:
<script type="text/javascript"> EventUtil.addHandler(window, "haschange", function (event) { console.log("Current hash:" + location.hash); })</script>
可以这样检测浏览器是否支持 hashchange 事件:
var isSupported = ("onhashchange" in window) && (document.documentMode == undefined || document.documentMode > 7);console.log(isSupported);
因为 IE8 是在 IE7 文档模式下运行的,所以即使功能无效它也会返回 true,所以上面的检测必须针对这一情况进行特殊处理。
- 说说 JavaScript 事件流之事件类型(包含 DOM2、DOM3 级事件)
- DOM0,DOM2,DOM3事件,事件基础知识入门
- DOM0,DOM2,DOM3事件处理方式区别
- js javascript 事件流 DOM2
- 说说 JavaScript 事件流之模拟事件
- JavaScript DOM0、DOM2级事件简述
- JavaScript之事件类型(事件)
- 说说 JavaScript 的事件流
- DOM2级点击事件的事件流的阻止
- DOM3 textInput事件-softbar
- DOM3 textInput事件-softbar
- JS事件--事件处理程序之DOM2事件处理程序
- javaScript中的DOM0级和DOM2级事件
- 关于JavaScript DOM2级事件捕获和冒泡
- javascript DOM详解之DOM2与DOM3
- Javascript学习笔记之dom2&&dom3
- 我之见于Javascript中DOM0级处理和DOM2级处理事件的区别
- 红宝书 第12章整理——DOM2和DOM3,非事件
- 浅析jQuery的基础设计模式
- 二叉树和二叉查找树
- C语言可以干些什么?C语言主要涉及哪些IT领域?
- Sublime Text Build 3126 x64 安装
- zkw线段树
- 说说 JavaScript 事件流之事件类型(包含 DOM2、DOM3 级事件)
- C# Lambda表达式
- Java多态的理解
- Android Vector Drawable | SVG 矢量图
- java Service和Servlet的区别 概念透析
- 提高C/C++运行效率以及避免出现Bug的20种方法
- 类加载机制
- 作为大型网站架构必须考虑的十大问题
- 一句话就看出他有没有教养