js高级程序设计读书笔记之——事件
- 事件流:
事件捕获(document->html->body)->处于目标阶段(事件在div上发生)->事件冒泡(div->body->html->document). - 在 HTML 中指定事件处理程序的缺点
- 扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。
- 存在加载时差问题:用户可能会在HTML 元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件;在解析事件函数(定义在文档最底部、按钮下方时)之前就触发,会报错。因此最好将事件处理程序被封装在 try-catch 块中,如:
<input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}">
- 大多数情况将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。
最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。
事件捕获常用于处理鼠标拖放、事件取消技术、程序调试等情况。 - IE中的attachEvent()
- 使用DOM0级事件与attachEvent()事件的区别:作用域不同——使用 attachEvent() 方法,事件处理程序会在全局作用域中运行,因此 this 等于window;DOM0 级对每个事件只支持一个事件处理程序。
- attachEvent() 添加多个事件时执行顺序为逆序,与addEventListener()的多个事件执行顺序刚好相反。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id); //"myBtn"
};
//IE中
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
5.只有在事件处理程序执行期间, event 对象才会存在;一旦事件处理程序执行完成, event 对象就会被销毁。
6 . 事件类别:
- load:在创建新的 img 元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。要在指定 src 属性之前先指定事件.
EventUtil.addHandler(window, "load", function(){
var image = document.createElement("img");
EventUtil.addHandler(image, "load", function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
document.body.appendChild(image);
image.src = "smile.gif";
});
//跨浏览器事件对象
var EventUtil = {
addHandler: function(element, 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){
// 省略的代码
},
stopPropagation: function(event){
if (event.stopPropagation){
event.stopPropagation(); //取消进一步的事件捕获或冒泡
} else {
event.cancelBubble = true;
}
}
};
- textInput:当用户在可编辑区域中输入字符时,就会触发这个事件。event.data表示输入的字符。
7 . 每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。
8 . 事件委托
- 改善事件处理过多的问题,提升性能。利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
- 使用事件委托,只需在DOM 树中尽量最高的层次上添加一个事件处理程序。此方式操作DOM节点变少,添加的事件处理程序变少,占用的内存更少。
- 最适合采用的事件包括 click 、mousedown 、 mouseup、 keydown 、keyup 和 keypress
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});
9 . 空事件处理程序:过期不用的事件处理程序,占用内存。主要有以下两种情况
- 从文档中移除带有事件处理程序的元素时:
如果带有事件处理程序的元素被 innerHTML 删除了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收.因为在 div元素上设置 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 = "Processing...";//按钮被移除
};
</script>
- 卸载页面的时候
在页面被卸载之前没有清理干净事件处理程序,那它们就会滞留在内存中。每次加载完页面再卸载页面时(两个页面间来回切换,或单击刷新按钮),内存中滞留的对象数目就会增加,因为事件处理程序占用的内存并没有被释放。
—解决:
- 通过 onunload 事件处理程序移除所有事件处理程序。
- 应用事件委托,通过把事件处理程序指定给较高层次的元素,减少需要跟踪的事件处理程序,方便移除。 使用 onunload 事件处理程序意味着页面不会被缓存在 bfcache 中。
10 . 模拟事件
用于web测试,模拟触发事件。如下为模拟对按钮单击事件的流程:
var btn = document.getElementById("myBtn");// 创建事件对象
var event = document.createEvent("MouseEvents");// 初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);
// 触发事件
btn.dispatchEvent(event);