13.事件
13.1.事件流
- 事件流描述的是从页面中接收事件的顺序,两家公司定义完全相反
13.1.1.事件冒泡
- 事件开始时由最具体的元素(文档中潜逃层次最深的节点)接收,然后逐级向上传播到较为不具体的节点
13.1.2.事件捕获
- 不太具体的节点更早接收到事件,而最具体的节点应该最后接收到事件
13.1.3.DOM事件流
- "DOM2级事件"规定的事件流包括三个阶段:事件捕获、处于目标阶段和事件冒泡阶段
- "DOM2级事件"规范要求捕获阶段不会涉及事件目标
13.2.事件处理程序
13.2.1.HTML事件处理程序
-
形式
-
<input type="button" value="Click Me" οnclick="alert("hello")">
-
<input type="button" value="Click Me" onclick="showMessage()"> <script type="text/javascript"> function showMessage(){ alert("hello world!") } </script>
-
-
事件处理函数中:
- 可以通过 event 变量直接访问事件对象
- 函数内部的 this 值等于时间的目标元素
-
扩展作用域:
<input type="button" value="Click Me" onclick="alert(value)">
13.2.2.DOM0级事件处理程序
-
形式
var btn = document.getElementById("myBtn"); btn.onclick = function() { alert("Clicked"); }; // 解绑 btn.click = null;
-
缺点
- HTML和JS耦合太强
- 一个元素无法同时绑定多个处理函数
13.2.3.DOM2级事件处理程序
-
特点:可以为一个元素添加多个事件处理程序
-
形式
// 最后一个参数true表示事件在捕获阶段触发,false表示在冒泡阶段触发,默认为false var btn = document.getElementById("myBtn"); btn.addEventListener("click", function() { alert(this.id); }, false); // 解绑事件 btn.removeEventListener("click", function() { alert(this.id); }, false); // 错误的解绑方式
// 正确的解绑方式 var btn = document.getElementById("myBtn"); var handler = function() { alert(this.id); }; btn.addEventListener("click", handler, false); btn.removeEventListener("click", handler, false);
13.2.4.IE事件处理程序
-
IE8及之前不支持DOM事件流,只支持事件冒泡
-
形式
// 注意此方法中的this等于window var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function() { alert(this === window); // true }); // 此方法也可以为一个元素添加多个事件处理程序,只不过触发顺序与DOM2级相反 // 解绑方式与DOM2相同
13.2.5.跨浏览器的事件处理程序
var EventUtil = {
addHandler: function(element, type, handler) {
if(element.addEventListener) {
element.addEventListener(type, hander, false);
}else if (element.attachEvent) {
element.attachEvent("on"+type, handler);
}else {
element["on"+type] = handler;
}
},
removeHandler: function(element, type, handler) {
if(element.removeEventListener) {
element.removeEventListener(type, hander, false);
}else if (element.detachEvent) {
element.detachEvent("on"+type, handler);
}else {
element["on"+type] = handler;
}
}
}
13.3.事件对象
13.3.1.DOM中的事件对象
-
阻止特定事件的默认行为
var link = document.getElementById("myLink"); link.onclick = function(event) { event.preventDefault(); }
-
立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡
event.stopPropagation();
13.3.2.IE中的事件对象
window.event
13.3.3.跨浏览器的事件对象
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.preventDefalut) {
evvent.preventDefault();
}else {
event.returnValue = false;
}
},
removeHandler: function (element, type, handler) {
if(element.removeEventListener) {
element.removeEventListener(type, hander, false);
}else if (element.detachEvent) {
element.detachEvent("on"+type, handler);
}else {
element["on"+type] = handler;
}
},
stopPropagation: function (event) {
if(event.stopPropagation) {
event.stopPropagation();
}else {
event.cancelBubble = true;
}
}
};
13.4.事件类型#
13.4.1.UI事件
13.4.2.焦点事件
13.4.3.鼠标与滚轮事件
13.4.4.键盘与文本事件
13.4.5.复合事件
13.4.6.变动事件
13.4.7.HTML5事件
13.4.8.设备事件
13.4.9.触摸与手势事件
13.5.内存和性能
- 每个函数都是对象,都会占用内存
- 内存中对象越多,性能就越差
13.5.1.事件委托
-
解决事件处理程序过多的问题
-
利用了事件冒泡的原理
-
实现
<ul id="myLinks"> <li id="goSomewhere">Go somewhere</li> <li id="doSomething">Do something</li> <li id="sayHi">Say hi</li> </ul> <script> 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; } }); </script>
13.5.2.移除事件处理程序
-
空事件处理程序
-
从文档中移除带有事件处理程序的元素
<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>
-
卸载页面之前没有清理干净事件处理程序,它们滞留在内存中 ?
-
13.6.模拟事件#
-
模拟事件步骤
// 创建事件对象 var btn = document.getElementById("myBtn"); var event = document.createEvent("MouseEvents"); // 初始化事件对象 event.initMouseEvent("click", [参数]); // 触发事件 btn.dispatchEvent(event);
-
自定义DOM事件
- DOM3级还定义了"自定义事件",目的是让开发人员创建自己的事件
var div = document.getElementById("myDiv"), event; EventUtil.addHandler(div, "myevent", function(event){ alert("DIV:" + event.detail); }); EventUtil.addHandler(document, "myevent", function(event){ alert("DOCUMENT:" + event.detail); }); if(document.implementation.hasFeature("CustomEvents", "3.0")) { event = document.createEvent("CUstomEvents"); event.initCustomEvent("myevent", true, false, "Hello world!"); div.dispatchEvent(event); }
-
IE中的事件模拟