转载:http://jiangzhengjun.javaeye.com/blog/480996
事件
DOM同时支持两种事件模式:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触及DOM中的所有对象,从document对象开 始,也在document对象结束(大部分兼容标准的浏览会继续将事件捕获/冒泡延续至window对象),DOM中的元素都会连续收到两次事件,一次在 捕获过程中,另一次在冒泡过程中。DOM事件模型最独特的性质是,文本节点也触发事件(在IE中不会)。点击文本节点事件流应该如下图:
传统事件处理函数有两种分配方式:在JavaScript中或者在HTML中。
在JavaScript中分配事件处理函数:
- var oDiv = document.getElementById( "div1" );
- oDiv.onclick = function () {
- alert("I was clicked" );
- };
注:在这个分配方法,事件处理函数名称必须小写,才能正确响应事件。
在HTML中分配事件处理函数:
- < div onclick = 'alert("I was clicked")' > </ div >
<div οnclick='alert("I was clicked")'> </div>
说明:用这种方法,事件处理函数的大小写可任意,所以onclick等同于onClick、OnClick或ONCLICK,但标准的事 件处理函数应该全部用小写定义。
说明:传统分配方式有个缺陷就是只能分配一个处理函数。于是就出现了其它以下分配方式。
IE中特有的attachEvent()事件处理函数分配方 式:
- var fnClick1 = function () {
- alert("Clicked!" );
- };
- var fnClick2 = function () {
- alert("Also clicked!" );
- };
- var oDiv = document.getElementById( "div" );
- oDiv.attachEvent("onclick" , fnClick1); //绑定事件处理函数
- oDiv.attachEvent("onclick" , fnClick2);
- //do something ...
- oDiv.detachEvent("onclick" , fnClick1); //解除事件处理函数
- oDiv.detachEvent("onclick" , fnClick2);
说明:事件处理函数总是按照添加它们的顺序进行调用。
DOM中的事件处理函数绑定
DOM 中方法addEventListener()和removeEventListener()用来分配与移除事件处理函数。与IE不同,需三个参数:事件 名、要分配的处理函数、处理函数是用于冒泡阶段还是捕获阶段,如果是捕获阶段,第三个参数为true。
- var fnClick1 = function () {
- alert("Clicked!" );
- };
- var oDiv = document.getElementById( "div" );
- oDiv.addEventListener("onclick" , fnClick1, false ); //绑定事件处 理函数
- //do something ...
- oDiv.removeEventListener("onclick" , fnClick1, false ); //解除事件处 理函数
说明:也可绑定多个函数,但要注意的是第三个参数删除时 要与添加时一样才能真真删除掉函数 ,否则删除不掉,也不会报错。
传统方式oDiv.onclick = fnClick; 与oDiv.addEventListener('onclick',fnClick1,false); 等 价。
事件对象的属性与方法
鼠标 / 键盘属性
属性 | 描述 | IE | F | O | W3C |
altKey | 返回当事件被触发时, "ALT" 是否被按下。 | 6 | 1 | 9 | Yes |
button | 返回当事件被触发时,哪个鼠标按钮被点击。 | 6 | 1 | 9 | Yes |
clientX | 鼠标指针相对于当前窗口的水平坐标。 | 6 | 1 | 9 | Yes |
clientY | 鼠标指针相对于当前窗口的垂直坐标。 | 6 | 1 | 9 | Yes |
ctrlKey | 返回当事件被触发时, "CTRL" 键是否被按 下。 | 6 | 1 | 9 | Yes |
metaKey | 返回当事件被触发时, "meta" 键是否被按 下。 | No | 1 | 9 | Yes |
relatedTarget | 对于 mouseover 事件来 说,该属性是鼠标指针移到目标节点上时所离开的那个节点。对于 mouseout 事件来 说,该属性是离开目标时,鼠标指针进入的节点。 | No | 1 | 9 | Yes |
screenX | 事件发生时鼠标指针相对于屏幕的水平坐标。 | 6 | 1 | 9 | Yes |
screenY | 鼠标指针相对于屏幕的垂直坐标。 | 6 | 1 | 9 | Yes |
shiftKey | 返回当事件被触发时, "SHIFT" 键是否被按 下。 | 6 | 1 | 9 | Yes |
IE 属性
除了上面的鼠标 / 事件属性, IE 浏 览器还支持下面的属性:
属性 | 描述 |
cancelBubble | 如果事件句柄想阻止事件传播到包容对象,必须把该属性设为 true 。 |
fromElement | 对于 mouseover 和 mouseout 事 件, fromElement 引用移出鼠标的元素。 |
keyCode | 对于 keypress 事件,该 属性声明了被敲击的键生成的 Unicode 字符编码。对于 keydown 和 keyup 事 件,它指定了被敲击的键的虚拟键盘代码。虚拟键盘码可能和使用的键盘的布局相关。 |
offsetX,offsetY | 发生事件的地点在事件源元素的坐标系统中的 x 坐 标和 y 坐标。 |
returnValue | 如果设置了该属性,它的值比事件句柄的返回值优先级高。把这个属性设置为 fasle , 可以取消发生事件的源元素的默认动作。 |
srcElement | 对于生成事件的 Window 对象、 Document 对 象或 Element 对象的引用。 |
toElement | 对于 mouseover 和 mouseout 事 件,该属性引用移入鼠标的元素。 |
x,y | 事件发生的位置的 x 坐标和 y 坐 标,它们相对于用 CSS 动态定位的最内层包容元素。 |
标准 Event 属性
下面列出了 2 级 DOM 事 件标准定义的属性。
属性 | 描述 | IE | F | O | W3C |
bubbles | 如果事件是起泡类型,则返回 true ,否则返回 fasle 。 | No | 1 | 9 | Yes |
cancelable | 如果用 preventDefault() 方 法可以取消与事件关联的默认动作,则为 true ,否则为 fasle 。 | No | 1 | 9 | Yes |
currentTarget | 返回其监听器触发事件的节点,即当前处理该事件的元素、文档或窗口。在捕获和起泡阶 段,该属性是非常有用的,因为在这两个节点,它不同于 target 属性。 | No | 1 | 9 | Yes |
eventPhase | 回事件传播的当前阶段。它的值是 1 、 2 、 3 三 个常量之一,它们分别表示捕获阶段、正常事件派发和起泡阶段。 |
|
|
| Yes |
target | 返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。 | No | 1 | 9 | Yes |
timeStamp | 返回事件生成的日期和时间。 | No | 1 | 9 | Yes |
type | 返回发生的事件的类型,即当前 Event 对象表示的事 件的名称。 它与注册的事件句柄同名,或者是事件句柄属性删除前缀 "on" 比 如 "submit" 、 "load" 或 "click" 。 | 6 | 1 | 9 | Yes |
标准 Event 方法
下面列出了 2 级 DOM 事 件标准定义的方法。 IE 的事件模型不支持这些方法:
方法 | 描述 | IE | F | O | W3C |
initEvent() | 初始化新创建的 Event 对象的属性。 | No | 1 | 9 | Yes |
preventDefault() | 通知浏览器不要执行与事件关联的默认动作。 | No | 1 | 9 | Yes |
stopPropagation() | 终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处 理程序将被调用,事件不再被分派到其他节点。 | No | 1 | 9 | Yes |
事件对象
包含的信息如下:
引 起事件的对象、事件发生时鼠标的信息、事件发生时键盘的信息。
事件对象只在发生事件时才被创建,且只有事件处理函数才能访问。处理完毕就会被销毁。
IE中,事件对象是window对象的一个属性event。 采用如下方式进行访问:
- oDiv.onclick = function () {
- var oEvent = window.event;
- };
DOM标准中,event对象必须作为唯一参数传 给事件处理函数,如下访问:
- oDiv.onclick = function () {
- var oEvent = arguments[0];
- };
当然此种方式可以直接通过参数传递进来:
- oDiv.onclick = function (oEvent){ //...}
IE与DOM获取事件属性相同的地方:
1、 获取事件类型(名称)
- function handleEvent(oEvent) {
- if (oEvent.type == "click" ) {
- alert("clicked" );
- } else {
- if (oEvent.type == "mouseover" ) {
- alert("mouse over" );
- }
- }
- }
- oDiv.onclick = handleEvent;
- oDiv.onmouseover = handleEvent;
2、 获取按键代码(keydown/keyup事件)
- var iKeyCode = oEvent.keyCode;
3、 检测是否按下了Shift、Alt、Ctrl键
- var bShift = oEvent.shiftKey;
- var bAlt = oEvent.altKey;
- var bCtrl = oEvent.ctrlKey;
4、 获取客户端鼠标事件坐标
- var iClientX = oEvent.clientX;
- var iClientY = oEvent.clientY;
说明:指与浏览器边界距离。
5、 获取鼠标距屏幕边沿坐标
- var iScreenX = oEvent.screenX;
- var iScreenY = oEvent.screenY;
IE与DOM获取事件属性不同的地方:
1、 获取目标(事件源)
IE:
- var oTarget = oEvent.srcElement;
DOM:
- var oTarget = oEvent.target;
2、 获取字符代码
IE 和DOM都支持event对象的keyCode属性,它会返回按下的按键的数值代码。但如果按键代表一个字符(但非Shift、Ctrl、Alt 等),IE的keyCode将返回字符的代码(等于它的Unicode值):
- var iCharCode = oEvent.keyCode;
在DOM兼容的浏览器中,按键代码与按键字符是分开的,要获取字符代码,请使用charCode属性:
- var iCharCode = oEvent.charCode;
如果不确定按下的按键是否包含字符,则可使用isChar属性来进行判断:
- if (oEvent.isChar){
- var iCharCode = oEvent.charCode;
- }
最后可以用这个值来获得实际的字符,只要使用String.fromCharCode()方法:
- var sChar = String.fromCharCode(iCharCode);
3、 阻止事件发生
IE:
- oEvent.returnValue = false ;
Mozilla:
- oEvent.preventDefault();
例如:附上使用上下文件菜单
- document.body.oncontextmenu = function (oEvnet) {
- if (isIE) {
- oEvnet = window.event;
- oEvnet.returnValue = false ;
- } else {
- oEvnet.preventDefault();
- }
- };
4、 停止事件冒泡
IE:
- oEvent.cancelBubble = true ;
Mozilla:
- oEvent.stopPropagation();
如下停止事件传播示例:
- < html onclick = "alert('html')" >
- < head >
- < title > Event Propagation Example </ title >
- < script type = "text/javascript" src = "detect.js" > </ script >
- < script type = "text/javascript" >
- function handleCick(oEvent) {
- alert("input");
- if (isIE) {
- oEvent.cancelBubble = true ;
- } else {
- oEvent.stopPropagation();
- }
- }
- </ script >
- </ head >
- < body onclick = "alert('body')" >
- < input type = 'button' value = 'Click Me' onclick = "handleCick (event)" />
- </ body >
- </ html >
<html οnclick="alert('html')">
<head>
<title>Event Propagation Example</title>
<script type="text/javascript" src="detect.js"> </script>
<script type="text/javascript">
function handleCick(oEvent) {
alert("input");
if (isIE) {
oEvent.cancelBubble = true;
} else {
oEvent.stopPropagation();
}
}
</script>
</head>
<body οnclick="alert('body')">
<input type='button' value='Click Me' οnclick="handleCick (event)" />
</body>
</html>
事件的类型
DOM标准定义了以下几组事件:
鼠标事件、键盘事件、HTML事件(窗口发生变动或者发生特定客户与服务器交互时触发)、突变事件(底层DOM结构发生改变时触发)
鼠标键盘事件
要 触发dblclick事件,在同一个目标上要按顺序发生以下事件:
mousedown、mouseup、click、mousedown、mouseup、click、dblclick
mouseout:用户正要将其移出元素的边界时发生。
mouseover:移入到某元素上时发生。
mousemove:鼠标 在某个元素移动时发生。
用户按一次某字符按键 时,会按以下发生事件:keydown、keypress、keyup
如果按某非字符键 (如Shift),按以下发生事件:keydown、keyup
如果用户按下一个字符按键且不放 ,keydown和keypress事件将逐个持续触发,直 到松开。
如果用户按下一个非字符按键且不放 ,将只有keydown事件持续触发。
HTML元素事件
load事件——页面完全载入后,在window对象上触发;所有的框架都载入后,在框架上集上触发; <img/>完全载入后,在其上触发;或者对于 <object/>元素,当其完全载入后在其上触发。
unload——页面完全卸载后,在window对象上触发;所有的框架都卸载后,在框架上集上触发; <img/>完全卸载后,在其上触发;或者对于 <object/>元素,当其完全卸载后在其上触发。
abort(异常中断)事件——用户停止下载过程时,如果 <object/>对象还未完全载入,就在其上触发。
error事件——JavaScript脚本出错时,在window对象上触发;某个 <img/>的指定图像无法载入时,在其上触发;或 <object/>元素无法载入时触发;或都框架集中的一个或多个框架无法载入时触发。
select事件——用户选择了文本框中的一个或多个字符时触发( <input/>或者 <textarea/>)。
change事件——文本框( <input/>或者 <textarea/>)失去焦点时并且在它获取焦点后内容发生过改变时触发;某个 <select/>元素的值发生改变时触发。
submit事件——点击提交按钮( <input type="submit"/>)时,在 <form/>上触发。
reset事件——点击重置按钮( <input type="reset"/>)时,在 <form/>上触发。
resize事件——窗口或者框架的大小发生改变时触发。
scrool事件——用户在任何带滚动条的元素上滚动它时触发。
focus事件——任何元素或者窗口本身获取焦点时触发。
blur事件——任何元素或者窗口本身失去焦点时触发。
load、unload事件
对于window对象可用 两种方法定义onload事件处理函数:
第一种:window.οnlοad=function(){//...}
第二种: <body οnlοad='alert()'/>
这两种是相同的,因为在HTML中没有window标签,所以就加在 <body/>元素上了。
注:不要使用document.body.οnlοad=function(){//...},如果把脚本放在 <head/>标签中,运行还会出错,显示document.body未定义,所以最后用window.onload
在窗口关闭到下一个页面获取控制之前,只有很短的时间来执行事件处理函数的代码,所以最好避免使用onunload事件处理函数。
跨平台的事件脚本
- /*
- * fileName:eventutil.js
- */
- var EventUtil = new Object;
- //添加事件处理函数
- EventUtil.addEventHandler = function (oTarget, sEventType, fnHandler) {
- if (oTarget.addEventListener) { //如果是支持DOM兼容浏览器
- //false 表示在冒泡阶段捕获
- oTarget.addEventListener(sEventType, fnHandler, false );
- } else {
- if (oTarget.attachEvent) { //如果是IE
- oTarget.attachEvent("on" + sEventType, fnHandler);
- } else { //其他浏览器
- oTarget["on" + sEventType] = fnHandler;
- }
- }
- };
- //删除事件处理函数
- EventUtil.removeEventHandler = function (oTarget, sEventType, fnHandler) {
- if (oTarget.removeEventListener) {
- oTarget.removeEventListener(sEventType, fnHandler, false );
- } else {
- if (oTarget.detachEvent) {
- oTarget.detachEvent("on" + sEventType, fnHandler);
- } else {
- oTarget["on" + sEventType] = null ;
- }
- }
- };
- //格式化event对象:把IE的event对象适配成DOM类似的事件对象。注:该方法不单独使用,仅供后面的 getEvent()方法使用
- EventUtil.formatEvent = function (oEvent) {
- if (isIE && isWin) {
- //由于IE所按的字符的编码是包含在keyCode属性中,所以如果事件类型是keypress,
- //需要创建charCode属性,值等于keyCode,否则为其他类型事件时设置成0
- oEvent.charCode = (oEvent.type == "keypress" ) ? oEvent.keyCode : 0;
- oEvent.eventPhase = 2;//这个属性始终等于2代表冒泡阶段,因为IE公支持这个阶段
- oEvent.isChar = (oEvent.charCode > 0);//当charCode不为0时为true
- oEvent.pageX = oEvent.clientX + document.body.scrollLeft;//鼠标距页面边的距离
- oEvent.pageY = oEvent.clientY + document.body.scrollTop;
- oEvent.preventDefault = function () { // 阻止事件适配 IE->DOM
- this .returnValue = false ;
- };
- //relatedTarget为DOM事件中的第二个事件目标
- if (oEvent.type == "mouseout" ) {
- //鼠标移出时为toElement(移向的那个对象)
- oEvent.relatedTarget = oEvent.toElement;
- } else {
- if (oEvent.type == "mouseover" ) {
- //鼠标移进时为fromElement(从哪个对象移进来的)
- oEvent.relatedTarget = oEvent.fromElement;
- }
- }
- //阻止事件冒泡
- oEvent.stopPropagation = function () {
- this .cancelBubble = true ;
- };
- //事件源适配
- oEvent.target = oEvent.srcElement;
- oEvent.time = (new Date).getTime();
- }
- return oEvent;
- };
- //该函数在事件处理函数中使用
- EventUtil.getEvent = function () {
- if (window.event) {
- return this .formatEvent(window.event);
- } else {
- /*函数是一个对象,event对象是一个函数,每个函数都有一个caller属性,它包含了指向调用它的方法
- 的引用。如,funcA()调用funcB(),那么funcB.caller就等于funcA。假设某 个事件处理函数调用了
- EventUtil.getEvent(), 那么EventUtil.getEvent.caller就指向这个事件处理函数的本身。
- 又函数有arguments属性,而event对象总是事件处理函数的第一个参数*/
- return EventUtil.getEvent.caller.arguments[0];
- }
- };
- < html >
- < head >
- < title > Mouse Events Example </ title >
- < script type = "text/javascript" src = "detect.js" > </ script >
- < script type = "text/javascript" src = "eventutil.js" > </ script >
- < script type = "text/javascript" >
- EventUtil.addEventHandler(window, "load", function () {
- var oDiv = document .getElementById("div1");
- EventUtil.addEventHandler(oDiv, "mouseover", handleEvent);
- EventUtil.addEventHandler(oDiv, "mouseout", handleEvent);
- EventUtil.addEventHandler(oDiv, "mousedown", handleEvent);
- EventUtil.addEventHandler(oDiv, "mouseup", handleEvent);
- EventUtil.addEventHandler(oDiv, "click", handleEvent);
- EventUtil.addEventHandler(oDiv, "dblclick", handleEvent);
- });
- function handleEvent() {
- var oEvent = EventUtil .getEvent();//通过EventUtil的 getEvent()方法获取IE中适配后的事件对象
- var oTextbox = document .getElementById("txt1");
- oTextbox.value += "/n> " + oEvent.type;
- //oEvent.target 其实是IE属性里的srcElement属性
- oTextbox.value += "/n target is " + oEvent.target.tagName;
- if (oEvent.relatedTarget) {
- //IE 事件对象中本没有relatedTarget属性,是由fromElement或toElement适配而来
- oTextbox.value += "/n relatedTarget is " + oEvent.relatedTarget.tagName;
- }
- }
- </ script >
- </ head >
- < body >
- < p >
- Use your mouse to click and double click the red square.
- </ p >
- < div style = "width: 100px; height: 100px; background-color: red"
- id = "div1" > </ div >
- < p >
- < textarea id = "txt1" rows = "15" cols = "50" > </ textarea >
- </ p >
- </ body >
- </ html >
<html>
<head>
<title>Mouse Events Example</title>
<script type="text/javascript" src="detect.js"></script>
<script type="text/javascript" src="eventutil.js"></script>
<script type="text/javascript">
EventUtil.addEventHandler(window, "load", function () {
var oDiv = document.getElementById("div1");
EventUtil.addEventHandler(oDiv, "mouseover", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseout", handleEvent);
EventUtil.addEventHandler(oDiv, "mousedown", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseup", handleEvent);
EventUtil.addEventHandler(oDiv, "click", handleEvent);
EventUtil.addEventHandler(oDiv, "dblclick", handleEvent);
});
function handleEvent() {
var oEvent = EventUtil.getEvent();//通过EventUtil的getEvent()方法获取IE中适配后的事件对象
var oTextbox = document.getElementById("txt1");
oTextbox.value += "/n>" + oEvent.type;
//oEvent.target其实是IE属性里的srcElement属性
oTextbox.value += "/n target is " + oEvent.target.tagName;
if (oEvent.relatedTarget) {
//IE事件对象中本没有relatedTarget属性,是由fromElement或toElement适配而来
oTextbox.value += "/n relatedTarget is " + oEvent.relatedTarget.tagName;
}
}
</script>
</head>
<body>
<p>
Use your mouse to click and double click the red square.
</p>
<div style="width: 100px; height: 100px; background-color: red"
id="div1"></div>
<p>
<textarea id="txt1" rows="15" cols="50"></textarea>
</p>
</body>
</html>