JavaScript 事件
一、基本概念
0x1 事件
1、定义
事件是可以被 JavaScript 侦测到的行为,通俗的讲就是当用户与Web页面进行某些交互时,解释器就会创建响应的event对象以描述事件信息。
2、事件句柄
事件句柄(又称事件处理函数、事件监听函数),指用于响应某个事件而调用的函数。每一个事件均对应一个事件句柄,在程序执行时,将相应的函数或语句指定给事件句柄,则在该事件发生时,浏览器便执行指定的函数或语句。
0x2 事件定义
一个事件的定义必须有三部:
- 事件对象
- 为事件对象绑定一个事件类型
- 事件句柄
为特定事件定义监听函数有三种方式:
(1)、直接在HTML中定义元素的事件相关属性
缺点:违反了“ 内容与行为相分离” 的原则,应尽可能少用。
1 2 3 |
<button onclick="alert('hello')">按钮</button> <body onload="init()">...</body> |
(2)、 DOM0级事件
在JavaScript中为元素的事件相关属性赋值:
缺点:此语法实现了“ 内容与行为相分离” ,但元素只能绑定一个监听函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<button id="myBtn">点击我</button> <script type="text/javascript"> var btn = document.getElementById("myBtn"); btn.onclick = function () { alert('Clicked'); } var btn = document.getElementById("myBtn"); btn.onclick = function () { alert(this.id); } </script> |
(3)、 DOM2级事件
高级事件处理方式,一个事件可以绑定多个监听函数
此语法可以为一个元素绑定多个监听函数,但需要注意浏览器兼容性问题
DOM2支持同一dom元素注册多个同种事件。
DOM2新增了捕获和冒泡的概念。
1 2 3 4 5 6 7 8 9 10 11 12 |
btn.addEventListener("click",function(){},false); // DOM btn.attachEvent("onclick",function(){}); // IE document.body.addEventListener("load",init); document.body.attachEvent("onload",init); function init(){ //... } Demo var btn = document.getElementById("myBtn"); btn.addEventListener("click", function () { alert(this.id); }, false); |
0x3 DOM事件流
1、添加移除事件
- addEventListener()
- removeEventListener()
1 2 3 4 5 6 |
element.addEventListener(event, function, useCapture) event : 必须。字符串,指定事件名。 function:必须。指定要事件触发时执行的函数。 useCapture:可选。布尔值,指定事件是否在捕获或冒泡阶段执行 //要想移除事件成功必须要保证addEventListener和removeEventListener里面的所有参数一致,匿名函数一般不可以 |
2、IE事件流
- attachEvent()
- detachEvent()
1 2 3 4 5 |
语法:element.attachEvent(event, function) 功能:用于向指定元素添加事件句柄 event : 必须。字符串,指定事件名,必须加“on” 前缀。 function:必须。指定要事件触发时执行的函数。 |
事件绑定与移除的兼容性代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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] = null } }, 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 } } } var btn = document.getElementById("myBtn"); var handler = function () { alert("Clicked"); } EventUtil.addHandler(btn, "click", handler); EventUtil.removeHandler(btn, "click", handler); |
3、事件周期
解释器创建一个event对象后,会按如下过程将其在HTML元素间进行传播
- 第一阶段:事件捕获,事件对象沿DOM树向下传播
- 第二阶段:目标触发,运行事件监听函数
- 第三阶段:事件冒泡,事件沿DOM树向上传播
事件的冒泡处理机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<div id="parent"> <div id="child" class="child"></div> </div> <ul> <li>item1</li> <li>item2</li> <li>item3</li> <li>item4</li> <li>item5</li> <li>item6</li> </ul> <script type="text/javascript"> // 事件冒泡 document.getElementById("parent").addEventListener("click", function (e) { alert("parent事件被触发," + this.id); }) document.getElementById("child").addEventListener("click", function (e) { alert("child事件被触发," + this.id) }) // 事件捕获 document.getElementById("parent").addEventListener("click", function (e) { alert("parent事件被触发," + e.target.id); }, true) document.getElementById("child").addEventListener("click", function (e) { alert("child事件被触发," + e.target.id) }, true) // 看个小案例 // 这个是利用事件冒泡 $("ul").on("mouseover", function (e) { $(e.target).css("background-color", "#ddd").siblings().css("background-color", "white"); }) // 不利用事件捕获,貌似没有任何区别 $("li").on("mouseover", function () { $(this).css("background-color", "#ddd").siblings().css("background-color", "white"); }) // 但是$("li")已经遍历了li,还有就是如果我们要插入一个新的li,那么还要给li重新添加事件,性能太差 $("li").on("mouseover", function () { $(this).css("background-color", "#ddd").siblings().css("background-color", "white"); }) // 如果插入一个li $("ul").on("mouseover", function () { $("<li>item7</li>").appendTo("ul"); // item7直接具有事件,无需重新绑定事件 }) $("li").on("mouseover", function () { $("<li>item7</li>").appendTo("ul"); // item7是不具有事件的,需要重新绑定事件 }) </script> |
4、Event对象
- type:事件的类型;
- srcElement/target:事件源,就是发生事件的元素;
- cancelBubble:布尔属性,设为true的时候,将停止事件进一步起泡到包容层次的元素;(e.cancelBubble = true; 相当e.stopPropagation(););
- returnValue:布尔属性,设置为false的时候可以组织浏览器执行默认
的事件动作;(e.returnValue = false; 相当于 e.preventDefault(););
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
<button id="myBtn">点击我</button> <script type="text/javascript"> // 都含有event事件 var btn = document.getElementById("myBtn"); btn.onclick = function (event) { alert(event.type); } btn.addEventListener = function (event) { alert(event.type); } // target和currentTarget var btn = document.getElementById("myBtn"); btn.onclick = function (event) { alert(event.currentTarget === this); //true alert(event.target === this); //true } document.body.onclick = function (event) { alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(event.target === document.getElementById("myBtn")); //true } // type的作用 var btn = document.getElementById("myBtn"); var handler = function (event) { switch (event.type) { case "click": alert("Clicked"); 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; // 阻止默认行为 var link = document.getElementById("myLink"); link.onclick = function (event) { event.preventDefault(); } // 取消事件捕获或者冒泡 var btn = document.getElementById("myBtn"); btn.onclick = function (event) { alert("Clicked"); event.stopPropagation(); } document.body.onclick = function (event) { alert("Body clicked"); } // eventPhase var btn = document.getElementById("myBtn"); btn.onclick = function (event) { alert(event.eventPhase); //2 事件处理程序处于目标对象上 } document.body.addEventListener("click", function (event) { alert(event.eventPhase); //1 捕获阶段调用的事件处理程序 }, true); document.body.onclick = function (event) { alert(event.eventPhase); //3 冒泡阶段调用的事件处理程序 } </script> |