事件
事件是由浏览器动作(如浏览器载入文档onload)和用户动作(如点击onclick)触发所产生得人机交互瞬间。
事件流
描述事件从页面到接受处理的流程
事件流感性认知
<!DOCTYPE html>
<html lang="en" id="html" onclick="Ht()">
<head>
<meta charset="UTF-8">
<title>事件流</title>
</head>
<body id="body" onclick="Bo()">
<div id="div" onclick="Di()">
<button id="button" onclick="Bu()">点我</button>
</div>
</body>
<script>
function Bu() {console.log("我是button");}
function Di() {console.log("我是div");}
function Bo() {console.log("我body");}
function Ht() {console.log("我是html");}
</script>
</html>
结果:
这里我只点击了button
,但是所有点击事件全部被触发了。感性认识,可能想:因为button
包在div
,div
包在body
,body
包在html
,所以我点击button
,也就相当于点击了他们,所以就触发。然而追根述源,只这是DOM事件流模型的其中一种,简称事件冒泡。
DOM事件流模型
事件冒泡
由目标元素上所产生的动作为事件触发源,然后事件层层向其父代递交,直至到document
节点,期间可能产生连锁的事件触发,如上述代码结果button->div->body->html->document。【微软提出】
事件捕捉
与上述完全相反document->html->body->div->button,下面直接代码演示。【网景提出】
代码:
<!DOCTYPE html>
<html lang="en" id="html">
<head>
<meta charset="UTF-8">
<title>事件流</title>
</head>
<body id="body">
<div id="div">
<button id="button">点我</button>
</div>
</body>
<script>
var html = document.getElementById("html"),
body = document.getElementById("body"),
div = document.getElementById("div"),
button = document.getElementById("button");
html.addEventListener("click", Ht, true);
body.addEventListener("click", Bo, true);
div.addEventListener("click", Di, true);
button.addEventListener("click", Bu, true);
function Bu() {console.log("我是button");}
function Di() {console.log("我是div");}
function Bo() {console.log("我body");}
function Ht() {console.log("我是html");}
</script>
结果完全相反。
note:
1)、所有现代浏览器都支持事件冒泡,但在具体实现中略有差别:
IE5.5及更早版本中事件冒泡会跳过元素(从body直接跳到document)。
IE9、Firefox、Chrome、和Safari则将事件一直冒泡到window对象。
2)、IE9、Firefox、Chrome、Opera、和Safari都支持事件捕获。尽管DOM标准要求事件应该从document对象开始传播,但这些浏览器都是从window对象开始捕获事件的。
3)、由于老版本浏览器不支持,很少有人使用事件捕获。建议使用事件冒泡。
事件流的三个阶段
事件捕捉阶段:由外部动作触发到传递到目标元素最近的父节点的过程,途中不会接受事件。
处于目标元素阶段:从事件传入到目标元素之初,到未接收事件之末的过程。
冒泡阶段:从事件接受处理触发之初,到事件递交document节点之末的过程,途中接受事件。
示意图:
事件代理【利用事件冒泡】
如果一个父节点内含有多个子节点,并且每个子节点都存在同一事件类型(如onclick)。我们可以为其父代设置一个事件处理器(onclick),来避免为其每个子代设置一个事件处理器,降低内存,提高性能。
代码
<!DOCTYPE html>
<html lang="en" id="html">
<head>
<meta charset="UTF-8">
<title>事件流</title>
</head>
<body>
<ul id="ul" onclick="show(event)">
<li>11</li>
<li>22</li>
<li>33</li>
<li>44</li>
</ul>
</body>
<script>
function show (e) {
//事件target属性:返回事件的目标节点(简称触发节点)
var tagname = e.target;
if (tagname.nodeName = "li")
alert(tagname.innerHTML);
}
</script>
</html>
如果想要阻止某个子代的事件发生,可以:
<script>
function show(e) {
//事件target属性:返回事件的目标节点(简称触发节点)
var tagname = e.target;
if (tagname.nodeName = "li") {
if (tagname.innerHTML == '22')
//阻止事件的处理
e.stopPropagation();
else
alert(tagname.innerHTML);
}
}
</script>
菜鸟爬行中…