一、事件流
事件流包括三个阶段:事件捕获阶段、处于目标阶段、时间冒泡阶段。
如图:捕获阶段是逐级向下,由不具体到具体节点;冒泡阶段是逐级向上传播到不具体的节点
二、事件处理程序
1、HTML事件处理程序
通过使用一个与相应事件处理程序同名的HTML特性来指定
2、DOM0级事件处理程序
将一个函数赋值给一个事件处理程序属性(每个元素都有自己的事件处理程序属性)
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert("hi");
};
使用DOM0级方法指定的事件处理程序是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行,即this引用当前的元素
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert(this.id);
};
删除事件处理程序
btn.onclick = null;
3、DOM2级事件处理程序
addEventListener()
和removeEventListener()
用于处理指定和删除事件处理程序的操作。接收3个参数:事件名、事件处理函数、布尔值。如果布尔值是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
var btn = document.getElementById('myBtn');
btn.addEventListener("click", function() {
alert(this.id);
}, false);
//事件处理程序是在元素的作用域中运行,即this引用当前的元素
通过addEventListener()
添加的事件处理程序只能用removeEventListener()
移除;移除时传入的参数与添加处理程序时使用的参数相同。(添加的匿名函数无法移除)
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); //有效
4、IE事件处理程序(IE8及更早版本)
attachEvent()
和detachEvent()
,接收2个参数:事件名、事件处理函数
除了事件处理程序的作用域不一样外,其他类似。IE事件处理程序在全局作用域中运行
var btn = document.getElementById('myBtn');
var handler = function() {
alert(this === window);
};
btn.attachEvent("onclick", handler); //true
btn.detachEvent("onclick", handler);
5、跨浏览器的事件处理程序
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, 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, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
//使用EventUtil对象
var btn = document.getElementById('myBtn');
var handler = function() {
alert("hi");
};
EventUtil.addHandler(btn, "click", handler);
三、事件对象
1、DOM中的事件对象
在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标
如果将事件处理程序指定给了目标元素,则this、currentTarget、target包含的值相同
var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
alert(this === event.currentTarget); //true
alert(this === event.target); //true
};
如果事件处理程序存在于父节点中,单击当前元素时
var btn = document.getElementById('myBtn');
document.body.onclick = function(event) {
alert(document.body === event.currentTarget); //true
alert(document.body === this); //true
alert(btn = event.target); //true
};
使用type属性,通过一个函数处理多个事件
var btn = document.getElementById('myBtn');
var handler = function(event) {
switch(event.type) {
case "click":
alert("hi");
break;
case "mouseover":
event.target.style.backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
preventDefault()
方法,阻止特定事件的默认行为(只有在cancelable属性为true时才能使用)
var link = document.getElementById('myLink');
link.onclick = function(event) {
event.preventDefault();
};
stopPropagation()
方法,取消事件的进一步捕获和冒泡(只有在cancelable属性为true时才能使用)
var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
alert("hi");
event.stopPropagation();
};
document.body.onclick = function(event) {
alert("hi again");
};
//如果不使用stopPropagation(),单击按钮时,就会先后出现两次警告框
2、IE中的事件对象
在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。即window.event
var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
var event = window.event;
alert(event.type);
};
//通过window.event取得event对象
使用attachEvent()
添加事件处理程序时,event对象作为参数被传入事件处理函数
var btn = document.getElementById('myBtn');
btn.attachEvent("onclick", function(event) {
alert(event.type);
});
srcElement属性,表示事件的目标(与DOM中的target属性相同)
var btn = document.getElementById('myBtn');
btn.onclick = function() {
alert(window.event.srcElement === this); //true
};
//都指向btn元素
btn.attachEvent("onclick", function(event) {
alert(event.srcElement === this); //false
});
//event.srcElement指向btn元素,this指向全局作用域window
returnValue属性,默认为true,设置为false时可以取消事件的默认行为(与DOM中的preventDefault()方法相同)
var link = document.getElementById('myLink');
link.onclick = function() {
window.event.returnValue = false;
};
cancelBubble属性,与DOM中的stopPropagation()方法类似,默认为false,设置为true时可以取消事件的冒泡
var btn = document.getElementById('myBtn');
btn.onclick = function() {
alert("hi");
window.event.cancelBubble = true;
};
document.body.onclick = function() {
alert("hi again");
};
//设置为true,单击按钮,只显示一个警告框
3、跨浏览器的事件对象
var EventUtil = {
getEvent: function(event) { //取得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;
}
},
stopPropagation: function(event) { //阻止事件流
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
四、事件委托
只指定一个事件处理程序,就可以管理某一类型的所有事件
- do something
- go somewhere
- say hi
传统:
var item1 = document.getElementById('dosomething');
var item2 = document.getElementById('gosomewhere');
var item3 = document.getElementById('sayhi');
EventUtil.addHandler(item1, "click", function(event) {
document.title = "other title";
});
EventUtil.addHandler(item2, "click", function(event) {
location.href = "http://baidu.com";
});
EventUtil.addHandler(item3, "click", function(event) {
alert("hi");
});
事件委托:
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 = "other title";
break;
case "gosomewhere":
location.href = "http://baidu.com";
break;
case "sayhi":
alert("hi");
break;
}
});