前言 :
在页面中,JS 和 HTML 之间的各种交互,是通过一系列的事件去实现的。那么我们就必须要去掌握 JS 中的 事件,事件流,事件冒泡,事件捕获,事件委托 等知识。
- 事件 ?
事件:是文档或浏览器窗口中发生的一些特定的交互问题。
- 事件流 ?
事件流:描述的是页面中接受事件的顺序,它分为两种,事件冒泡和事件捕获,现在主流为事件冒泡。IE9,chrome,Firefox,Opera,Safari 均实现了 DOM2 级规范中定义的标准 DOM 事件,而 IE8 和 IE8 以下版本仍然保留专有的事件处理方式。
- 事件冒泡 ?
事件冒泡:即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播。
在一个对象上触发某类事件(比如单击 onclick 事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即 document 对象(有些浏览器window)。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<style type="text/css">
#myDiv{
width:100px;
height:100px;
background-color:#FF0000;
}
</style>
<body>
<div id="myDiv"></div>
</body>
<script type="text/javascript">
var div=document.getElementById("myDiv");
div.onclick=function(event){
alert("div");
};
document.body.onclick=function(event){
alert("body");
};
</script>
</html>
实例解析:当用户点击了 <div> 元素,click 事件将按照 <div>—><body>—><html>—>document 的顺序进行传播。若在<div> 和 <body> 上都定义了click事件,点击<div>,将先输出 “div”,再输出 “body”。IE9,chrome,Firefox,Opera,Safari 都支持事件冒泡,并将事件冒泡到 window 对象。
- 事件捕获 ?
事件捕获:是先由最上一级的节点先接收事件,然后向下传播到具体的节点。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<style type="text/css">
#myDiv{
width:100px;
height:100px;
background-color:#FF0000;
}
</style>
<body>
<div id="myDiv"></div>
</body>
<script type="text/javascript">
var div=document.getElementById("myDiv");
div.addEventListener("click",function(event){
alert("div");
},true);
document.body.addEventListener("click",function(event){
alert("body");
},true);
</script>
</html>
实例解析:采用事件捕获,则 click 事件将按照 document—><html>—><body>—><div> 的顺序进行传播。若在 <div>和<body> 上都定义了 click 事件,点击 <div>,将先输出“body”,再输出 “div”。IE9,chrome,Firefox,Opera,Safari 都支持事件捕获,但是 IE8 和 IE8 以下的版本只支持事件冒泡。尽管 DOM2 规范要求事件应该从 document 对象开始传播,但是现在的浏览器实现都是从 window 对象开始捕获事件。
- DOM 事件流 ?
"DOM2级事件”:规定的事件流包含三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,然后是实际的目标接收到事件,最后阶段是冒泡阶段。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<style type="text/css">
#myDiv{
width:100px;
height:100px;
background-color:#FF0000;
}
</style>
<body>
<div id="myDiv"></div>
</body>
<script type="text/javascript">
var div=document.getElementById("myDiv");
div.onclick=function(event){
alert("div");
};
document.body.addEventListener("click",function(event){
alert("event bubble");
},false);
document.body.addEventListener("click",function(event){
alert("event catch");
},true);
</script>
</html>
实例解析:若在 <div> 和 <body> 上都定义了 click 事件,点击 <div>,将先输出 “event catch”,再输出 “div”,最后输出 “event bubble”。
- 事件委托机制 ?
事件委托机制:由冒泡事件衍生出的事件委托机制,既然事件是冒泡传递的,那可以让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理。就是将子元素的事件处理程序绑定到父类上,例如常见的ul>li> a 列表标签的写法应用。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<body>
<ul>
<li id="ll">选项一</li>
<li>选项二</li>
<li>选项三</li>
<li>选项四</li>
</ul>
</body>
<script type="text/javascript">
$("ul").on("mouseover", function () {
console.log(event.target);
var lis = document.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
if (event.target && event.target == lis[i]) {
$(event.target).css("background-color", "#ffff00").siblings().css("background-color", "#1d7b15");
}
}
});
</script>
</html>
- 阻止冒泡 ?
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation ) {
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
}else{
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}
- 阻止事件默认行为 ?
//阻止浏览器的默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault ){
e.preventDefault();
//IE中阻止函数器默认动作的方式
}else{
window.event.returnValue = false;
}
return false;
}
- jQuery 阻止事件冒泡 ?
// 方法1
$("#div1").mousedown(function(event){
event.stopPropagation();
});
// 方法2
$("#div1").mousedown(function(event){
return false;
});
【注意】:这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。在 jq 下,即阻止默认行为又停止冒泡。js 原生下,阻止默认行为,不会停止冒泡。