`

JavaScript的事件DOM

阅读更多
<script type="text/javascript"></script>

 

事件(上)

 

(不好意思,又是标题党)

 

JavaScript事件列表
事件 解说
一般事件 onclick 鼠标点击时触发此事件
ondblclick 鼠标双击时触发此事件
onmousedown 按下鼠标时触发此事件
onmouseup 鼠标按下后松开鼠标时触发此事件
onmouseover 当鼠标移动到某对象范围的上方时触发此事件
onmousemove 鼠标移动时触发此事件
onmouseout 当鼠标离开某对象范围时触发此事件
onkeypress 当键盘上的某个键被按下并且释放时触发此事件.
onkeydown 当键盘上某个按键被按下时触发此事件
onkeyup 当键盘上某个按键被按放开时触发此事件
页面相关事件 onabort 图片在下载时被用户中断
onbeforeunload 当前页面的内容将要被改变时触发此事件
onerror 出现错误时触发此事件
onload 页面内容完成时触发此事件
onmove 浏览器的窗口被移动时触发此事件
onresize 当浏览器的窗口大小被改变时触发此事件
onscroll 浏览器的滚动条位置发生变化时触发此事件
onstop 浏览器的停止按钮被按下时触发此事件或者正在下载的文件被中断
oncontextmenu 当弹出右键上下文菜单时发生
onunload 当前页面将被改变时触发此事件
表单相关事件 onblur 当前元素失去焦点时触发此事件
onchange 当前元素失去焦点并且元素的内容发生改变而触发此事件
onfocus 当某个元素获得焦点时触发此事件
onreset 当表单中RESET的属性被激发时触发此事件
onsubmit 一个表单被递交时触发此事件

了解上面的事件如此简单,那么事件还有什么可讲的呢?

问题一:每个事件只能注册一个函数

 

 

Js代码 复制代码
  1. var oDiv = document.getElementById("oDiv");   
  2. oDiv.onclick = fn1;   
  3. oDiv.onclick =fn2;   
  4. function fn1() {alert("我被覆盖了!")}   
  5. function fn2() {alert("只有我被执行到!")}  
	var oDiv = document.getElementById("oDiv");
	oDiv.onclick = fn1;
	oDiv.onclick =fn2;
	function fn1() {alert("我被覆盖了!")}
	function fn2() {alert("只有我被执行到!")}
 

 

 

解决方案一:

 

 

Js代码 复制代码
  1. obj.onclick = function () {   
  2.     fn1();   
  3.     fn2();   
  4.     fn3();   
  5. };  
	obj.onclick = function () {
		fn1();
		fn2();
		fn3();
	};
 

 

 

 

缺陷一:需要将所有函数一次添加进去,不能在运行时添加

缺陷二:在事件处理函数中this将指向window,而不是obj

解决方案二:

 

 

Js代码 复制代码
  1. function addEvent(fn,evtype,obj) {   
  2.     //obj是要添加事件的HTML元素对象   
  3.     //evtype是事件名字,不包含on前缀,因为每个都有on,所以写个on是多余的   
  4.     //fn是事件处理函数   
  5.     var oldFn;   
  6.     if (obj["on"+evtype] instanceof Function) {   
  7.         oldFn = obj["on"+evtype];//当添加函数时,如果已注册过了,则将其保存起来   
  8.     }   
  9.     obj["on"+evtype]=function () {   
  10.             if (oldFn) {   
  11.                 oldFn.call(this);   
  12.             }   
  13.             fn.call(this);//使用call方法,使事件处理函数中的this仍指向obj   
  14.     };   
  15. }  
	function addEvent(fn,evtype,obj) {
		//obj是要添加事件的HTML元素对象
		//evtype是事件名字,不包含on前缀,因为每个都有on,所以写个on是多余的
		//fn是事件处理函数
		var oldFn;
		if (obj["on"+evtype] instanceof Function) {
			oldFn = obj["on"+evtype];//当添加函数时,如果已注册过了,则将其保存起来
		}
		obj["on"+evtype]=function () {
				if (oldFn) {
					oldFn.call(this);
				}
				fn.call(this);//使用call方法,使事件处理函数中的this仍指向obj
		};
	}
 

 

 

这样已经解决了问题,但如何删除事件呢?如果直接将对象的onevtype这类的属性赋值为null将会删除所有的事件处理函数!

解决方案二的修改版:先将事件存储起来,存储在对象的__EventHandles属性里面

 

 

Js代码 复制代码
  1. eventHandlesCounter=1;//计数器,将统计所有添加进去的函数的个数,0位预留作其它用   
  2. function addEvent(fn,evtype,obj) {   
  3.     if (!fn.__EventID) {//__EventID是给函数加的一个标识,见下面给函数添加标识的部分   
  4.         fn.__EventID=eventHandlesCounter++;   
  5.         //使用一个自动增长的计数器作为函数的标识以保证不会重复   
  6.     }   
  7.     if (!obj.__EventHandles) {   
  8.         obj.__EventHandles=[];//当不存在,也就是第一次执行时,创建一个,并且是数组   
  9.     }   
  10.     if (!obj.__EventHandles[evtype]) {//将所有事件处理函数按事件类型分类存放   
  11.         obj.__EventHandles[evtype]={};//当不存在时也创建一个散列表   
  12.                       if (obj["on"+evtype] instanceof Function) {   
  13.             //查看是否已经注册过其它函数   
  14.             //如果已经注册过,则将以前的事件处理函数添加到下标为0的预留的位置   
  15.             obj.__EventHandles[evtype][0]=obj["on"+evtype];   
  16.             obj["on"+evtype]=handleEvents;//使用handleEvents集中处理所有的函数   
  17.         }   
  18.     }   
  19.     obj.__EventHandles[evtype][fn.__EventID]=fn;   
  20.     //如果函数是第一次注册为事件处理函数,那么它将被添加到表中,函数的标识作为下标   
  21.     //如果函数已经注册过相同对象的相同事件了,那么将覆盖原来的而不会被添加两次   
  22.     function handleEvents() {   
  23.         var fns = obj.__EventHandles[evtype];   
  24.         for (var i in fns) {   
  25.             fns[i].call(this);   
  26.         }   
  27.     }   
  28. }  
	eventHandlesCounter=1;//计数器,将统计所有添加进去的函数的个数,0位预留作其它用
	function addEvent(fn,evtype,obj) {
		if (!fn.__EventID) {//__EventID是给函数加的一个标识,见下面给函数添加标识的部分
			fn.__EventID=eventHandlesCounter++;
			//使用一个自动增长的计数器作为函数的标识以保证不会重复
		}
		if (!obj.__EventHandles) {
			obj.__EventHandles=[];//当不存在,也就是第一次执行时,创建一个,并且是数组
		}
		if (!obj.__EventHandles[evtype]) {//将所有事件处理函数按事件类型分类存放
			obj.__EventHandles[evtype]={};//当不存在时也创建一个散列表
                       if (obj["on"+evtype] instanceof Function) {
				//查看是否已经注册过其它函数
				//如果已经注册过,则将以前的事件处理函数添加到下标为0的预留的位置
				obj.__EventHandles[evtype][0]=obj["on"+evtype];
				obj["on"+evtype]=handleEvents;//使用handleEvents集中处理所有的函数
			}
		}
		obj.__EventHandles[evtype][fn.__EventID]=fn;
		//如果函数是第一次注册为事件处理函数,那么它将被添加到表中,函数的标识作为下标
		//如果函数已经注册过相同对象的相同事件了,那么将覆盖原来的而不会被添加两次
		function handleEvents() {
			var fns = obj.__EventHandles[evtype];
			for (var i in fns) {
				fns[i].call(this);
			}
		}
	}
 

 

 

使用上面的函数已经可以在一个对象添加多个事件处理函数,在函数内部this关键字也指向了相应的对象,并且这些函数都被作了标识,那么移除某个事件处理函数就是轻而易举的了!

 

 

Js代码 复制代码
  1. //使用传统方法:obj.onevtype = null;但这样会移除所有的事件处理函数   
  2.     function delEvent(fn,evtype,obj) {   
  3.         if (!obj.__EventHandles || !obj.__EventHandles[evtype] || !fn.__EventID) {   
  4.             return false;   
  5.         }   
  6.         if (obj.__EventHandles[evtype][fn.__EventID] == fn) {   
  7.             delete obj.__EventHandles[evtype][fn.__EventID];   
  8.         }   
  9.     }  
//使用传统方法:obj.onevtype = null;但这样会移除所有的事件处理函数
	function delEvent(fn,evtype,obj) {
		if (!obj.__EventHandles || !obj.__EventHandles[evtype] || !fn.__EventID) {
			return false;
		}
		if (obj.__EventHandles[evtype][fn.__EventID] == fn) {
			delete obj.__EventHandles[evtype][fn.__EventID];
		}
	}

 

 

 

 

 

 

-------------------------------------------------新手的分隔线----------------------------------------------------------------

 

 

事件(下)

事件对象——Event

事件对象是用来记录一些事件发生时的相关信息的对象。事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁!

访问事件对象:W3C DOM方法与IE专用方法

 

Js代码 复制代码
  1. //W3C DOM把事件对象作为事件处理函数的第一个参数传入进去   
  2.     document.onclick = function (evt) {//这样,事件对象只能在对应的事件处理函数内部可以访问到   
  3.         alert(evt);   
  4.     };   
  5.     //IE将事件对象作为window对象的一个属性(相当于全局变量)   
  6.     //貌似全局对象,但是只有是事件发生时才能够访问   
  7.     alert(window.event);//null   
  8.     window.onload = function () {   
  9.         alert(window.event);   
  10.     };  
//W3C DOM把事件对象作为事件处理函数的第一个参数传入进去
	document.onclick = function (evt) {//这样,事件对象只能在对应的事件处理函数内部可以访问到
		alert(evt);
	};
	//IE将事件对象作为window对象的一个属性(相当于全局变量)
	//貌似全局对象,但是只有是事件发生时才能够访问
	alert(window.event);//null
	window.onload = function () {
		alert(window.event);
	};
 

 

 

事件对象的属性及方法

鼠标相关 属性名 值类型 读/写 描述
button Integer R

对于特定的鼠标事件,表示按下的鼠标按钮,该属性仅可以在mouseup与mousedown事件中访问。W3C 规定:0表示按下了左键,1表示按下了中键,2表示按下了右键,相当于对于鼠标键从左到右进行的编号,而编号从0开始; 而IE有另外一套规定:0表示没有任何键按下,1表示左键,2表示右键,4表示中键,而其它按键的组合则只要将键码相加即可,如:同时按下左右键时button值为3

clientX Integer R 事件发生时,鼠标在客户端区域的X坐标,客户端区域是指页面可视区域
clientY Integer R 事件发生时,鼠标在客户端区域的Y坐标
screenX Integer R(IE) R/W(W3C) 相对于屏幕的鼠标X坐标
screenY Integer R(IE) R/W(W3C) 相对于屏幕的鼠标Y坐标
x(仅IE) Integer R 鼠标相对于引起事件的元素的父元素的X坐标
y(仅IE) Integer R 鼠标相对于引起事件的元素的父元素的Y坐标
offsetX(仅IE) layerX(仅W3C) Integer R 鼠标相对于引起事件的对象的X坐标
offsetY(仅IE) layerY(仅W3C) Integer R 鼠标相对于引起事件的对象的Y坐标
pageX(仅W3C) Integer R 鼠标相对于页面的X坐标
pageY(仅W3C) Integer R 鼠标相对于页面的Y坐标
键盘相关 属性名 值类型 读/写 描述
altKey Boolean R true表示按下了ALT键;false表示没有按下
ctrlKey Boolean R true表示按下了CTROL,false表示没有
shiftKey Boolean R true表示按下了shift,false表示没有
keyCode Integer R/W(IE) R(W3C) 对于keypress事件,表示按下按钮的Unicode字符;对于keydown/keyup事件 ,表示按下按钮的数字代号
charCode(仅W3C) Integer R 在keypress事件中所按键的字符Unicode编码,如果不是字符键,则该属性为0,并且,当CapsLock打开与关闭时charCode的值也对应着大小写字母
其它 属性名 值类型 读/写 描述
srcElement(IE) target(W3C) Element R 引起事件的元素
fromElement(仅IE) Element R 某些鼠标事件中(mouseover与mouseout),鼠标所离开的元素
toElement(仅IE) Element R 某些鼠标事件中(mouseover与mouseout),鼠标所进入的元素
relatedTarget(仅W3C) Element R 某些鼠标事件中(mouseover与mouseout),返回与事件的目标节点相关的节点。
repeat(仅IE) Boolean R 如果不断触发keydown事件,则为true,否则为false
returnValue(仅IE) Boolean R/W 将其设为false表示以取消事件的默认动作
preventDefault(仅W3C) Function R 执行方法以取消事件的默认动作
type String R 事件的名称,不带on前缀
cancelable(仅W3C ) Boolean R 当为true表示事件的默认动作可以被取消(用preventDefault方法取消)
cancelBubble(仅IE) Boolean R/W 将其设置为true将取消事件冒泡
stopPropagation(仅W3C) Function R 执行方法取消事件冒泡
bubbles(仅W3C) Boolean R 返回true表示事件是冒泡类型
eventPhase(仅W3C) Integer R 返回事件传播的当前阶段。它的值是下面的三个常量之一,它们分别表示捕获阶段、在目标对象上时和起泡阶段: 常量 值
Event.CAPTURING_PHASE(捕获阶段) 1
Event.AT_TARGET(在目标对象上) 2
Event.BUBBLING_PHASE(冒泡阶段) 3
timeStamp (仅W3C) Long R 返回一个时间戳。指示发生事件的日期和时间(从 epoch 开始的毫秒数)。epoch 是一个事件参考点。在这里,它是客户机启动的时间。并非所有系统都提供该信息,因此,timeStamp 属性并非对所有系统/事件都是可用的。

取得事件对象及取得事件目标对象

 

 

Js代码 复制代码
  1. document.onclick =function (evt) {   
  2.         evt = evt || window.event;//在IE中evt会是undefined   
  3.         //而支持W3C DOM事件的浏览器中事件对象将会作为事件处理函数的第一个参数   
  4.         var targetElement = evt.target || evt.srcElement;   
  5.         //IE中事件对象没有target属性   
  6.     };  
document.onclick =function (evt) {
		evt = evt || window.event;//在IE中evt会是undefined
		//而支持W3C DOM事件的浏览器中事件对象将会作为事件处理函数的第一个参数
		var targetElement = evt.target || evt.srcElement;
		//IE中事件对象没有target属性
	};
 

 

 

 

阻止事件发生时浏览器的默认行为

 

 

Js代码 复制代码
  1. document.onclick = function (evt) {   
  2.     evt = evt || window.event;   
  3.     var target = evt.target || evt.srcElement;   
  4.     if (!target) {   
  5.         return;   
  6.     }   
  7.     if (target.tagName=="A" && target.href) {   
  8.         //使用传统的方法取消事件默认行为必须使用return false   
  9.         //但使用了return ,函数便终止了运行,可以使用事件对象来取消   
  10.         if (window.event) {//IE   
  11.             window.event.returnValue = false;   
  12.         } else {   
  13.             evt.preventDefault();   
  14.         }   
  15.         window.open(target.href,"newWindow");   
  16.         //这样让所有的链接在新窗口打开   
  17.     }   
  18. };   
	document.onclick = function (evt) {
		evt = evt || window.event;
		var target = evt.target || evt.srcElement;
		if (!target) {
			return;
		}
		if (target.tagName=="A" && target.href) {
			//使用传统的方法取消事件默认行为必须使用return false
			//但使用了return ,函数便终止了运行,可以使用事件对象来取消
			if (window.event) {//IE
				window.event.returnValue = false;
			} else {
				evt.preventDefault();
			}
			window.open(target.href,"newWindow");
			//这样让所有的链接在新窗口打开
		}
	};
	
 

 

 

 

事件传播——冒泡与捕获

DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响。这两种事件流分别是捕获和冒泡。和许多Web技术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们。Netscape选择实现了捕获事件流,微软则实现了冒泡事件流。幸运的是,W3C决定组合使用这两种方法,并且大多数新浏览器都遵循这两种事件流方式。

默认情况下,事件使用冒泡事件流,不使用捕获事件流。然而,在Firefox和Safari里,你可以显式的指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true。

冒泡事件流

当事件在某一DOM元素被触发时,例如用户在客户名字节点上点击鼠标,事件将跟随着该节点继承自的各个父节点冒泡穿过整个的DOM节点层次,直到它遇到依附有该事件类型处理器的节点,此时,该事件是onclick事件。在冒泡过程中的任何时候都可以终止事件的冒泡,在遵从W3C标准的浏览器里可以通过调用事件对象上的stopPropagation()方法,在Internet Explorer里可以通过设置事件对象的cancelBubble属性为true。如果不停止事件的传播,事件将一直通过DOM冒泡直至到达文档根。

捕获事件流

事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有祖先元素依次往下传递。在这个过程中,事件会被从文档根到事件目标元素之间各个继承派生的元素所捕获,如果事件监听器在被注册时设置了useCapture属性为true,那么它们可以被分派给这期间的任何元素以对事件做出处理;否则,事件会被接着传递给派生元素路径上的下一元素,直至目标元素。事件到达目标元素后,它会接着通过DOM节点再进行冒泡。

现代事件绑定方法

针对如上节课所讨论的,使用传统事件绑定有许多缺陷,比如不能在一个对象的相同事件上注册多个事件处理函数。而浏览器和W3C也并非没有考虑到这一点,因此在现代浏览器中,它们有自己的方法绑定事件。

W3C DOM

  • obj.addEventListener(evtype,fn,useCapture)——W3C提供的添加事件处理函数的方法。obj是要添加事件的对象,evtype是事件类型,不带on前缀,fn是事件处理函数,如果useCapture是true,则事件处理函数在捕获阶段被执行,否则在冒泡阶段执行
  • obj.removeEventListener(evtype,fn,useCapture)——W3C提供的删除事件处理函数的方法

微软IE方法

  • obj.attachEvent(evtype,fn)——IE提供的添加事件处理函数的方法。obj是要添加事件的对象,evtype是事件类型,带on前缀,fn是事件处理函数,IE不支持事件捕获
  • obj.detachEvent(evtype,fn,)——IE提供的删除事件处理函数的方法,evtype包含on前缀

整合两者的方法

 

 

Js代码 复制代码
  1. function addEvent(obj,evtype,fn,useCapture) {   
  2.     if (obj.addEventListener) {   
  3.         obj.addEventListener(evtype,fn,useCapture);   
  4.     } else {   
  5.         obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获   
  6.     } else {   
  7.         obj["on"+evtype]=fn;//事实上这种情况不会存在   
  8.     }   
  9. }   
  10. function delEvent(obj,evtype,fn,useCapture) {   
  11.     if (obj.removeEventListener) {   
  12.         obj.removeEventListener(evtype,fn,useCapture);   
  13.     } else {   
  14.         obj.detachEvent("on"+evtype,fn);   
  15.     } else {   
  16.         obj["on"+evtype]=null;   
  17.     }   
  18. }  
	function addEvent(obj,evtype,fn,useCapture) {
		if (obj.addEventListener) {
			obj.addEventListener(evtype,fn,useCapture);
		} else {
			obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获
		} else {
			obj["on"+evtype]=fn;//事实上这种情况不会存在
		}
	}
	function delEvent(obj,evtype,fn,useCapture) {
		if (obj.removeEventListener) {
			obj.removeEventListener(evtype,fn,useCapture);
		} else {
			obj.detachEvent("on"+evtype,fn);
		} else {
			obj["on"+evtype]=null;
		}
	}
 

 

 

 

其它兼容性问题:IE不支持事件捕获?很抱歉,这个没有办法解决!但IE的attach方法有个问题,就是使用attachEvent时在事件处理函数内部,this指向了window,而不是obj!当然,这个是有解决方案的!

 

 

Js代码 复制代码
  1. function addEvent(obj,evtype,fn,useCapture) {   
  2.         if (obj.addEventListener) {   
  3.             obj.addEventListener(evtype,fn,useCapture);   
  4.         } else {   
  5.             obj.attachEvent("on"+evtype,function () {   
  6.                 fn.call(obj);   
  7.             });   
  8.         } else {   
  9.             obj["on"+evtype]=fn;//事实上这种情况不会存在   
  10.         }   
  11.     }  
function addEvent(obj,evtype,fn,useCapture) {
		if (obj.addEventListener) {
			obj.addEventListener(evtype,fn,useCapture);
		} else {
			obj.attachEvent("on"+evtype,function () {
				fn.call(obj);
			});
		} else {
			obj["on"+evtype]=fn;//事实上这种情况不会存在
		}
	}
 

 

 

但IE的attachEvent方法有另外一个问题,同一个函数可以被注册到同一个对象同一个事件上多次,解决方法:抛弃IE的 attachEvent方法吧!IE下的attachEvent方法不支持捕获,和传统事件注册没多大区别(除了能绑定多个事件处理函数),并且IE的 attachEvent方法存在内存泄漏问题!

addEvent,delEvent现代版

 

 

Js代码 复制代码
  1. function addEvent(obj,evtype,fn,useCapture) {   
  2.     if (obj.addEventListener) {//优先考虑W3C事件注册方案   
  3.         obj.addEventListener(evtype,fn,!!useCapture);   
  4.     } else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定   
  5.         if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;}   
  6.         //为每个事件处理函数分配一个唯一的ID   
  7.            
  8.         if (!obj.__EventHandles) {obj.__EventHandles={};}   
  9.         //__EventHandles属性用来保存所有事件处理函数的引用   
  10.            
  11.         //按事件类型分类   
  12.         if (!obj.__EventHandles[evtype]) {//第一次注册某事件时   
  13.             obj.__EventHandles[evtype]={};   
  14.             if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数   
  15.                 (obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位   
  16.                 //并且给原来的事件处理函数增加一个ID   
  17.             }   
  18.             obj["on"+evtype]=addEvent.execEventHandles;   
  19.             //当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数   
  20.         }   
  21.     }   
  22. }   
  23. addEvent.__EventHandlesCounter=1;//计数器,0位预留它用   
  24. addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行   
  25.     if (!this.__EventHandles) {return true;}   
  26.     evt = evt || window.event;   
  27.     var fns = this.__EventHandles[evt.type];   
  28.     for (var i in fns) {   
  29.             fns[i].call(this);   
  30.     }   
  31. };   
  32. function delEvent(obj,evtype,fn,useCapture) {   
  33.     if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数   
  34.         obj.removeEventListener(evtype,fn,!!useCapture);   
  35.     } else {   
  36.         if (obj.__EventHandles) {   
  37.             var fns = obj.__EventHandles[evtype];   
  38.             if (fns) {delete fns[fn.__EventID];}   
  39.         }   
  40.     }   
  41. }   
	function addEvent(obj,evtype,fn,useCapture) {
		if (obj.addEventListener) {//优先考虑W3C事件注册方案
			obj.addEventListener(evtype,fn,!!useCapture);
		} else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定
			if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;}
			//为每个事件处理函数分配一个唯一的ID
			
			if (!obj.__EventHandles) {obj.__EventHandles={};}
			//__EventHandles属性用来保存所有事件处理函数的引用
			
			//按事件类型分类
			if (!obj.__EventHandles[evtype]) {//第一次注册某事件时
				obj.__EventHandles[evtype]={};
				if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数
					(obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位
					//并且给原来的事件处理函数增加一个ID
				}
				obj["on"+evtype]=addEvent.execEventHandles;
				//当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数
			}
		}
	}
	addEvent.__EventHandlesCounter=1;//计数器,0位预留它用
	addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行
		if (!this.__EventHandles) {return true;}
		evt = evt || window.event;
		var fns = this.__EventHandles[evt.type];
		for (var i in fns) {
				fns[i].call(this);
		}
	};
	function delEvent(obj,evtype,fn,useCapture) {
		if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数
			obj.removeEventListener(evtype,fn,!!useCapture);
		} else {
			if (obj.__EventHandles) {
				var fns = obj.__EventHandles[evtype];
				if (fns) {delete fns[fn.__EventID];}
			}
		}
	}
	
 

 

 

标准化事件对象

IE的事件对象与W3C DOM的事件对象有许多不一样的地方,解决的最好的方法就是调整IE的事件对象,以使它尽可能的与标准相似!下表列出了IE事件对象中一些和W3C DOM名称或值不一样但含义相同的属性

IE与W3C DOM事件对象的不同 W3C DOM IE
button——按键编码为:0-左键,1-中键,2-右键 button——按键编码为:1-左键,2-右键,4-中键
charCode 没有对应属性,但可以用keyCode来代替
preventDefault 没有对应方法,但可以将event对象的returnValue设为false来模拟
target srcElement
relatedTarget fromElement与toElement
stopPropagation 没有对应方法,但可以通过将event对象的cancelBubble属性设为true来模拟

 

 

 

总结出fixEvent函数

 

 

Js代码 复制代码
  1. function fixEvent(evt) {   
  2.     if (!evt.target) {   
  3.         evt.target = evt.srcElement;   
  4.         evt.preventDefault = fixEvent.preventDefault;   
  5.         evt.stopPropagation = fixEvent.stopPropagation;   
  6.         if (evt.type == "mouseover") {   
  7.             evt.relatedTarget = evt.fromElement;   
  8.         } else if (evt.type =="mouseout") {   
  9.             evt.relatedTarget = evt.toElement;   
  10.         }   
  11.         evt.charCode =  (evt.type=="keypress")?evt.keyCode:0;   
  12.         evt.eventPhase = 2;//IE仅工作在冒泡阶段   
  13.         evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间   
  14.     }   
  15.     return evt;   
  16. }   
  17. fixEvent.preventDefault =function () {   
  18.     this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent   
  19. };   
  20. fixEvent.stopPropagation =function () {   
  21.     this.cancelBubble = true;   
  22. };  
	function fixEvent(evt) {
		if (!evt.target) {
			evt.target = evt.srcElement;
			evt.preventDefault = fixEvent.preventDefault;
			evt.stopPropagation = fixEvent.stopPropagation;
			if (evt.type == "mouseover") {
				evt.relatedTarget = evt.fromElement;
			} else if (evt.type =="mouseout") {
				evt.relatedTarget = evt.toElement;
			}
			evt.charCode =  (evt.type=="keypress")?evt.keyCode:0;
			evt.eventPhase = 2;//IE仅工作在冒泡阶段
			evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间
		}
		return evt;
	}
	fixEvent.preventDefault =function () {
		this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent
	};
	fixEvent.stopPropagation =function () {
		this.cancelBubble = true;
	};
 

 

fixEvent函数不是单独执行的,它必须有一个事件对象参数,而且只有事件发生时它才被执行!最好的方法是把它整合到addEvent函数的execEventHandles里面

 

 

 

Js代码 复制代码
  1. addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行   
  2.     if (!this.__EventHandles) {return true;}   
  3.     evt = fixEvent(evt || window.event);//在这里对其进行标准化操作   
  4.     var fns = this.__EventHandles[evt.type];   
  5.     for (var i in fns) {   
  6.             fns[i].call(this,evt);//并且将其作为事件处理函数的第一个参数   
  7.             //这样在事件处理函数内部就可以使用统一的方法访问事件对象了   
  8.     }   
  9. };  
	addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行
		if (!this.__EventHandles) {return true;}
		evt = fixEvent(evt || window.event);//在这里对其进行标准化操作
		var fns = this.__EventHandles[evt.type];
		for (var i in fns) {
				fns[i].call(this,evt);//并且将其作为事件处理函数的第一个参数
				//这样在事件处理函数内部就可以使用统一的方法访问事件对象了
		}
	};
 

 

 

Load事件

使用JavaScript操纵DOM,必须等待DOM加载完毕才可以执行代码,但window.onload有个坏处,它非要等到页面中的所有图片及视频加载完毕才会触发load事件。结果就是一些本来应该在打开时隐藏起来的元素,由于网络延迟,在页面打开时仍然会出现,然后又会突然消失,让用户觉得莫名其妙。

 

大师们想出来的方法:

 

 

Js代码 复制代码
  1. function addLoadEvent(fn) {   
  2.     var init = function() {   
  3.         if (arguments.callee.done) return;   
  4.         arguments.callee.done = true;   
  5.         fn.apply(document,arguments);   
  6.     };   
  7.     //注册DOMContentLoaded事件,如果支持的话   
  8.     if (document.addEventListener) {   
  9.         document.addEventListener("DOMContentLoaded", init, false);   
  10.     }   
  11.     //但对于Safari,我们需要使用setInterval方法不断检测document.readyState   
  12.     //当为loaded或complete的时候表明DOM已经加载完毕   
  13.     if (/WebKit/i.test(navigator.userAgent)) {   
  14.         var _timer = setInterval(function() {   
  15.             if (/loaded|complete/.test(document.readyState)) {   
  16.                 clearInterval(_timer);   
  17.                 init();   
  18.             }   
  19.         },10);   
  20.     }   
  21.     //对于IE则使用条件注释,并使用script标签的defer属性   
  22.     //IE中可以给script标签添加一个defer(延迟)属性,这样,标签中的脚本只有当DOM加载完毕后才执行   
  23.     /*@cc_on @*/  
  24.     /*@if (@_win32)  
  25.     document.write("<script id=\"__ie_onload\" defer=\"defer\" src=\"javascript:void(0)\"><\/script>");  
  26.     var script = document.getElementById("__ie_onload");  
  27.     script.onreadystatechange = function() {  
  28.         if (this.readyState == "complete") {  
  29.             init();  
  30.         }  
  31.     };  
  32.     /*@end @*/<
    分享到:
    评论

相关推荐

    JavaScript之DOM事件(源代码)

    JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源...

    JavaScript_DOM编程艺术第二版(中文)

    在DOM部分,书中详细讲解了DOM模型的层次结构,如何通过JavaScript访问和修改HTML元素,以及如何利用DOM事件来响应用户交互。理解DOM节点、属性、事件和选择器是创建动态网页的关键,这使得开发者能够动态加载内容、...

    JavaScript.DOM编程艺术(第2版)附录及源码.rar

    8. **DOM事件委托**:利用事件冒泡或事件捕获机制,可以有效地处理大量元素的事件,提高性能。 9. **DOM性能优化**:理解DOM操作的性能影响,如避免不必要的重绘和回流,使用文档碎片等技巧,能够提升网页性能。 ...

    JavaScript dom操作 dom元素查询 示例代码

    JavaScript dom操作 dom元素查询 示例代码JavaScript dom操作 dom元素查询 示例代码JavaScript dom操作 dom元素查询 示例代码JavaScript dom操作 dom元素查询 示例代码JavaScript dom操作 dom元素查询 示例代码...

    javascript_DOM操作.rar

    8. **DOM事件流**:DOM事件流包括捕获阶段、目标阶段和冒泡阶段。理解这个过程对于有效处理事件至关重要。 9. **事件委托**:利用事件冒泡,可以在父元素上设置监听器处理子元素的事件,减少内存消耗和代码冗余。 ...

    JavaScript DOM编程艺术【第2版&高清】.pdf

    5. DOM事件处理:JavaScript通过事件驱动进行交互。事件会在特定的动作(如点击、按键、加载等)发生时被触发,DOM提供了添加和移除事件监听器的接口。学习如何在DOM元素上绑定事件和编写事件处理函数是提高网页交互...

    JavaScript DOM编程艺术(第2版pdf)+源代码

    JavaScript DOM编程艺术(第2版)是一本深受程序员喜爱的JavaScript技术书籍,专注于讲解如何使用JavaScript与Document Object Model(DOM)进行交互。DOM是Web页面的结构化表示,它允许我们通过编程方式操纵HTML和XML...

    JavaScript DOM编程艺术.pdf

    《JavaScript DOM编程艺术》是Jeremy Keith所著的一本关于JavaScript和DOM(文档对象模型)编程的经典图书,它不仅阐述了JavaScript和DOM的基本知识,还着重讲解了DOM编程技术背后的思路和原则。本书被赞誉为Web设计...

    JavaScriptDOM编程艺术(第2版)PDF版本下载.txt

    根据提供的文件信息,我们可以推断出这是一本关于JavaScript DOM编程技术的书籍——《JavaScript DOM编程艺术(第2版)》。尽管实际书籍内容并未给出,但从标题、描述及部分链接信息来看,这本书主要涉及JavaScript...

    经典之作javascript dom编程艺术源码

    10. **DOM变更事件**:DOM操作如添加、删除元素时,会触发DOM事件,如`DOMNodeInserted`和`DOMNodeRemoved`,可以利用这些事件进行响应式编程。 通过学习并实践《JavaScript DOM编程艺术》中的源码,开发者能够掌握...

    Beginning JavaScript with DOM Scripting and Ajax: Second Editon

    Beginning JavaScript with DOM Scripting and Ajax is an essential resource for modern JavaScript programming. This completely updated second edition covers everything you need to know to get up-to-...

    随书光盘+PDF JavaScript DOM编程艺术(第2版)-源代码2.5MB PDF114MB .zip

    在书中,作者会详细介绍如何利用JavaScript与DOM进行交互,这包括选取元素(如通过选择器API或XPath),修改元素属性,以及处理事件。还会探讨如何使用CSS样式和JavaScript结合来实现动态布局和视觉效果。此外,书中...

    javascript_DOM操作

    4. **响应式设计**: 根据窗口大小调整元素布局,利用DOM事件监听窗口尺寸变化。 5. **拖放功能**: 实现元素的拖放操作,涉及事件监听和元素状态的改变。 6. **模板引擎**: 配合模板字符串和DOM操作,动态生成和...

    JavaScript dom操作 趣味案例

    本资源为JavaScript的dom操作的趣味案例,可直接打开查看本资源为JavaScript的dom操作的趣味案例,可直接打开查看本资源为JavaScript的dom操作的趣味案例,可直接打开查看本资源为JavaScript的dom操作的趣味案例,可...

    javaScript-DOM编程艺术

    DOM提供了一套API,包括节点操作(如创建、插入、删除节点)、事件处理(如点击、鼠标移动等)、属性访问等。例如,可以使用`appendChild()`方法在元素的末尾添加新子节点,`addEventListener()`来监听和响应用户...

    Javascript+DOM编程艺术(完整版).pdf

    《Javascript+DOM编程艺术(完整版)》是Jeremy Keith所著的一本关于前端开发技术的书籍,专注于Web设计中的JavaScript和DOM编程。本书被认为是前端开发者必读的经典之作,其清晰的文笔、遵循优秀的编程原则和严格的...

    JavaScript & DOM Enlightenment

    DOM Enlightenment可能涵盖了如何通过JavaScript访问和修改DOM节点,包括元素选择(如querySelector和querySelectorAll)、遍历DOM树、添加和删除元素、以及事件处理。此外,还可能涉及到性能优化技巧,如使用文档...

    JavaScript+DOM编程艺术(PDF格式原版+源代码)

    DOM编程艺术这部分内容将详细介绍如何使用JavaScript操作DOM树,包括查找、创建、修改和删除节点,以及如何绑定和处理事件。 书中的源代码包含了一系列与书中实例对应的练习,这些练习可以帮助读者巩固所学知识,...

    javascript Dom 编程艺术

    本 书在简洁明快地讲述JavaScript和DOM的基本知识之后,通过几个实例演示了专业水准的网页开发技术,透彻阐述了平稳退化等一批至关重要的 JavaScript编程原则和最佳实践,并全面探讨了HTML5以及jQuery等JavaScript库...

Global site tag (gtag.js) - Google Analytics