一、事件流
- 事件捕捉 :由document开始,一级一级向内捕捉事件,直到目标元素
- 事件冒泡 :由目标元素开始,一级一级向上冒泡,直到到达元素最外层
事件执行机制:
- 当页面发生某个事件时,先由最外层开始向内捕捉,直到找到事件目标元素;再由目标元素向上冒泡,直到到达元素最外层
- 为了兼容浏览器,一般情况下,我们将事件添加在冒泡阶段 (IE执行事件冒泡,其他浏览器执行事件捕捉)
二、事件处理程序
-
DOM0级事件处理程序
- 一个目标元素中不能同时存在两种事件,否则,后面的事件将覆盖前面的事件
- 支持 IE8
btn.onclick = function(){
// do something;
}
- DOM2级事件处理程序
- addEventListener(),接收三个参数:【eventName】— 事件名称,例如:click点击事件、mourseover-鼠标触及事件…;【handle】— 事件发生时的执行函数;【boolean】— 布尔值 true/false,该值为false时表示在事件冒泡阶段调用事件处理程序 一般建议在冒泡阶段使用,特殊情况才在捕捉阶段使用
btn.addEventListener("click", function(){
// do something;
}, false);
- 目标元素中可以同时存在多个事件,按添加顺序执行事件,但IE相反
myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);
- 支持 IE9+
- removeEventListener()移除事件,接收三个参数,必须与被移除事件的参数一致
myElement.removeEventListener('click', functionA);
三、事件对象
-
触发页面中的某个事件时,就会产生一个event,我们称之为 " 事件对象 ";而这个事件对象中包含了该事件的所有信息,如:【执行某事件的元素】【事件类型】【其他,例如:鼠标点击事件中鼠标的坐标值…等等】
-
“target”、“this”、“currentTarget”、"type"是事件对象中常用的属性,在《JS高级程序设计》中,有对所有属性和方法的讲解,这里只介绍几个常用属性
- target — 事件发生的实际目标元素 ,如下示例中,虽然将事件处理程序绑定在box元素中,但实际上事件是发生在按钮上的,由于事件捕捉,最后返回的是实际发生事件的元素 “button”;而currentTarget和this则指向事件绑定的元素
<div id="box"> <button id="btn">click me</button> </div> <script> var box = document.getElementById("box"); var btn = document.getElementById("btn"); box.onclick = function(event){ console.log(event.target.nodeName); // 返回 button console.log(event.currentTarget.nodeName); // 返回 div console.log(this.nodeName); // 返回 div } </script>
- 如果事件处理程序绑定的元素就是执行事件的元素,那么"target"、“this”、"currentTarget"三个属性都指向同一个元素
<script> var box = document.getElementById("box"); var btn = document.getElementById("btn"); btn.onclick = function(event){ console.log(event.target.nodeName); // 返回 button console.log(event.currentTarget.nodeName); // 返回 button console.log(this.nodeName); // 返回 button } </script>
- 如何使用事件对象,示例:点击li时,p标签的文本内容为li的背景色,文本颜色白色,背景色为li的背景色
<ul class="palette"> <li style="background-color:crimson"></li> <li style="background-color:bisque"></li> <li style="background-color:blueviolet"></li> <li style="background-color:coral"></li> <li style="background-color:chartreuse"></li> <li style="background-color:darkolivegreen"></li> <li style="background-color:cyan"></li> <li style="background-color:#194738"></li> </ul> <p class="color-picker"></p>
var list = document.getElementsByTagName("li"); for(var i=0; i<list.length; i++){ list[i].onclick = function(event){ var t = event.target; // 将事件的目标元素保存在变量t中,以备需要的时候直接调用 var p = document.getElementsByTagName("p")[0]; p.innerHTML = t.style.cssText; p.style.color = "#FFFFFF"; p.style.cssText += t.style.cssText; } }
- 阻止默认行为
event.preventDefault()
,比如一个a标签中的href属性是跳转到指定的页面,如果我们不想让它执行跳转行为,就可以为其添加阻止默认行为 - 阻断事件后续执行
event.stopPropagation()
,根据前面的冒泡及捕捉机制,如果给目标元素及其父元素都绑定了事件处理程序,那么触发目标元素时,实际上是触发的其父元素(事件冒泡机制),那么目标元素上的事件将永远不会被触发,解决这一情况,就要在目标元素中阻止事件冒泡 - 下面的例子中,当我们点击按钮时,应该是触发红色背景,可结果却触发蓝色背景,那是因为我们一方面给box绑定了事件处理程序,另一方面由于事件冒泡,最后执行了box的事件处理程序;
<div id="box"> <button id="btn">click me</button> </div> <p id="para">red</p>
var box = document.getElementById("box"); var btn = document.getElementById("btn"); btn.onclick = function(e){ var p = document.getElementById("para"); // 目标元素触发点击事件时,背景颜色是红色 p.style.cssText = "background-color:#cc0000; width:100px; height:100px; line-height:100px; text-align:center; color:#FFFFFF;"; } box.onclick = function(e){ var p = document.getElementById("para"); // 父元素触发事件时,背景颜色是蓝色 p.style.cssText = "background-color:#002cb9; width:100px; height:100px; line-height:100px; text-align:center; color:#FFFFFF;"; }
- 按照我们的思路,应该是触发红色背景,所以要将
stopPropagation()
放在按钮中,阻止它向上冒泡; stopPropagation()
不止是阻止事件冒泡,也可以阻止事件捕捉,实际就是阻止事件的后续行为;
btn.onclick = function(e){ var p = document.getElementById("para"); p.style.cssText = "background-color:#cc0000; width:100px; height:100px; line-height:100px; text-align:center; color:#FFFFFF;"; event.stopPropagation(); // 阻止事件向上冒泡 }