一、事件
事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。
事件是javaScript和DOM之间的桥梁。
你若触发,我便执行——事件发生,调用它的处理函数执行相应的JavaScript代码给出响应。
典型的例子有:页面加载完毕触发load事件;用户单击元素,触发click事件。
二、事件流
1、事件流感性认识
问题:单击页面元素,什么样的元素能感应到这样一个事件?
答案:单击元素的同时,也单击了元素的容器元素,甚至整个页面。
例子:有三个同心圆, 给每个圆添加对应的事件处理函数,弹出对应的文字。单击最里面的圆,同时也单击了外面的圆,所以外面圆的click事件也会被触发。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <style> #outer{ position: absolute; width: 400px; height: 400px; top:0; left: 0; bottom:0; right: 0; margin: auto; background-color: deeppink; } #middle{ position: absolute; width: 300px; height:300px; top:50%; left: 50%; margin-left: -150px; margin-top: -150px; background-color: deepskyblue; } #inner{ position: absolute; width: 100px; height:100px; top:50%; left:50%; margin-left: -50px; margin-top: -50px;; background-color: darkgreen; text-align: center; line-height: 100px; color:white; } #outer,#middle,#inner{ border-radius:100%; } </style> <body> <div id="outer"> <div id="middle"> <div id="inner"> click me! </div> </div> </div> <script> var innerCircle= document.getElementById("inner"); innerCircle.onclick= function () { alert("innerCircle"); }; var middleCircle= document.getElementById("middle"); middleCircle.onclick=function(){ alert("middleCircle"); } var outerCircle= document.getElementById("outer"); outerCircle.onclick= function () { alert("outerCircle"); } </script> </body> </html>
2、事件流
事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。
事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事件流。
冒泡型事件流:事件的传播是从最特定的事件目标到最不特定的事件目标。即从DOM树的叶子到根。
捕获型事件流:事件的传播是从最不特定的事件目标到最特定的事件目标。即从DOM树的根到叶子。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="myDiv">Click me!</div> </body> </html>
上面这段html代码中,单击了页面中的<div>元素,
在冒泡型事件流中click事件传播顺序为<div> —> <body>—> <html>—> document
在捕获型事件流中click事件传播顺序为document —> <html> —><body> —> <div>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <style> #outer { position: absolute; width: 400px; height: 400px; top: 0; left: 0; bottom: 0; right: 0; margin: auto; background-color: deeppink; } #middle { position: absolute; width: 300px; height: 300px; top: 50%; left: 50%; margin-left: -150px; margin-top: -150px; background-color: deepskyblue; } #inner { position: absolute; width: 100px; height: 100px; top: 50%; left: 50%; margin-left: -50px; margin-top: -50px; ; background-color: darkgreen; text-align: center; line-height: 100px; color: white; } #outer, #middle, #inner { border-radius: 100%; } </style> <body> <div id="outer"> <div id="middle"> <div id="inner"> click me! </div> </div> </div> <script> //true - 事件句柄在捕获阶段执行 //false- 事件句柄在冒泡阶段执行(默认) var innerCircle = document.getElementById("inner"); innerCircle.addEventListener("click", function() { alert("innerCircle的click事件在捕获阶段被触发"); }, true); innerCircle.addEventListener("click", function() { alert("innerCircle的click事件在冒泡阶段被触发"); }, false); var middleCircle = document.getElementById("middle"); middleCircle.addEventListener("click", function() { alert("middleCircle的click事件在捕获阶段被触发"); }, true); middleCircle.addEventListener("click", function() { alert("middleCircle的click事件在冒泡阶段被触发"); }, false); var outerCircle = document.getElementById("outer"); outerCircle.addEventListener("click", function() { alert("outerCircle的click事件在捕获阶段被触发"); }, true); outerCircle.addEventListener("click", function() { alert("outerCircle的click事件在冒泡阶段被触发"); }, false); </script> </body> </html>
3、事件流的典型应用——事件代理
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <body> <ul id="color-list"> <li>red</li> <li>orange</li> <li>yellow</li> <li>green</li> <li>blue</li> <li>indigo</li> <li>purple</li> </ul> <script> (function() { var colorList = document.getElementById("color-list"); colorList.addEventListener('click', showColor, false); function showColor(e) { e = e || window.event; var targetElement = e.target || e.srcElement; console.log(targetElement.nodeName.toLowerCase()); if (targetElement.nodeName.toLowerCase() === "li") { alert(targetElement.innerHTML); } } })(); </script> </body> </body> </html>
a、将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
b、DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。