1.在触发DOM上的某个事件时,会在事件处理程序函数中会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。先看个例子:
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert(event.type); //"click"
}
btn.addEventListener("click", function(event) {
alert(event.type); //"click"
}, false);
event.type属性表示事件类型。
event的属性currentTarget意思是事件处理程序当前正在处理事件的那个元素,target意思是事件的目标。在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。看个例子:
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert(event.currentTarget === this); //true
alert(event.target === this); //true
};
把事件处理程序直接指定给目标元素btn,则this、currentTarget和target包含相同的值。如果把事件处理程序注册在btn的父节点上(例如document.body),那么:
document.body.onclick = function(envent) {
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
target元素等于btn元素,因为它是click事件真正的目标,由于没有注册事件处理程序,结果click冒泡到document.body上,在那里事件得到了处理。
一个函数处理多个事件:
var btn = document.getElementById("myBtn");
var handler = function(event) {
switch(event.type) {
case "click":
alert("Clicked");
break;
case "mouseover":
event.target.style.backgroundColor = "blue";
break;
case "mouseout":
event.target.style.backgroundColor = "red";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
event有个preventDefault()方法,阻止特定事件的默认行为。
event.stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。例如:
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event) {
alert("Body Clicked");
};
如果不调用event.stopPropagation(),就会出现两个警告框。可是调用了这个方法后,click事件不会传播到document.body,因此就不会触发这个元素上的onclick事件处理程序。
2.再来看看IE中的事件对象
event对象作为window对象的一个熟悉存在。例子:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
var event = window.event;
alert(event.type); //"click"
};
btn.attachEvent("click", function(event) {
alert(event.type); //"click"
}); //也可以通过window取得event对象
IE中event获取事件目标的属性是srcElement,:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
var event = window.event;
alert(event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event) {
alert(event.srcElement === this); //false
});
因为this对象是根据事件处理程序的作用域确定的,所以上面两个不一样。
event.returnValue属性相当于DOM中的preventDefault()方法,只要将returnValue设置为false,就可以阻止默认行为:
var link = document.getElementById("myLink");
link.onclick = function() {
window.event.returnValue = false;
} //阻止链接默认行为
event.cancelBubble属性与DOM中的stopPropagation()方法作用相同,都是用来停止事件冒泡的。由于IE不支持事件捕获,因而只能取消事件冒泡,但stopPropagation()可以同时支持事件捕获和冒泡。
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function() {
alert("Body Clicked");
};
将cancelBubble设置为true,就可阻止事件通过冒泡而触发document.body中注册的事件处理程序,只出现一个警告框。
3.跨浏览器的事件对象
var EventUtil = {
getEvent: function(event) {
return event ? event : window.event;
},
getTarget: function(event) {
return event.target || event.srcElement;
},
preventDefault: fuction(event) {
if(event.preventDefaule()) {
event.preventDefaule();
} else {
event.returnValue = false;
}
},
stopPropagation: function(event) {
if(event.stopPropagation()) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
btn.onclick = function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event); //等等
}
4.如果事件处理程序过多,会占用内存,导致性能变差。解决办法是用事件委托。就是制定一个事件处理程序,管理某一类型的所有事件。例如:click事件会一直冒泡到document层次,就是说我们可以为整个页面制定一个onclick事件处理程序,而不必为每个单击的元素分别添加事件处理程序。例如:
<ul id="lists">
<li id="goSomewhere">Go</li>
<li id="doSomething">Do</li>
<li id="sayHi">Hi</li>
</ul>
var item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");
EventUtil.addHandler(item1, "click", function(event) {
location.href = "http://www.google.com";
});
EventUtil.addHandler(item2, "click", function(event) {
alert("Me");
});
EventUtil.addHandler(item3, "click", function(event) {
alert("Hi");
});
如果在一个复杂的web应用程序中都使用这种方式,那就会有无数的代码添加事件处理程序,然而可以 事件委托技术解决,就是在DOM树的尽量最高的层次添加一个事件处理程序:
var list = document.getElementById("lists");
EventUtil.addHandler(list, "click", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id) {
case "goSomewhere":
location.href = "http://www.google.com";
break;
case "doSomething":
alert("Me");
break;
case "sayHi":
alert("Hi");
break;
}
});
把事件委托给目标的父元素或者祖先元素,在ul添加添加一个onclick事件处理程序,由于所有目标元素都是这个元素的子节点,而且他们也会过得一个onclick事件,由于事件会冒泡,所以点击事件最终会被ul元素的处理事件程序处理。采用事件委托技术只添加了一个事件处理程序,占用的内存更少。
移除事件处理程序,在不需要的时候移除,也能提高性能,如果内存中留有那些过时不用的空事件处理程序,会造成内存和性能问题。
我们一般会用removeChild()和replaceChild()方法,但更多的是发生在使用innerHTML替换页面中的某一部分,如果把带有事件处理程序的元素用innerHTML替代原先的内容,那么原先添加到元素中的事件处理程序可能无法被当做垃圾回收。例子:
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function() {
//执行某些任务
document.getElementById("myDiv").innerHTML = "Changing...";
}
</script>
点击按钮就将按钮移除并替换成一个消息,在开发中很流行,但问题是,当按钮被从页面中移除时,它还带着一个事件处理程序。设置innerHTML可以把按钮移走,但事件处理程序仍然与按钮保持着引用关系,那么有些浏览器可能会把元素对事件处理程序的引用保存在内存中,生成了空事件处理程序,如果你知道某个事件即将被移除,那么最好手工处理:
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function() {
//执行某些任务
btn.onclick = null; //移除事件处理程序
document.getElementById("myDiv").innerHTML = "Changing...";
}
</script>