第十三章 事件
事件概念
JS与HTML之间的交互通过事件实现。事件就是文档或浏览器窗口中发生的一些的特定交互瞬间。可以使用侦听器(处理程序)来预定事件。以便事件发生时执行相应的代码。
事件流
事件流 描述的是从页面中接收事件的顺序。
I 事件冒泡
IE的事件流叫做事件冒泡,事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,逐级向上传播到较不具体的节点。
IE9.FF、chrome、safari冒泡到window对象。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Computed Styles Example</title> </head> <body <div id="myDiv">Click me!</div> </body> </html>
单击了DIV,那个这个click事件首先在div元素上发生,其次是body。click事件沿着DOM树向上传播。再每一个级节点上都会发生,直到document对象。
II事件捕获
由不太具体的节点应该更早接收的事件,而最具体的节点应该最后接收到事件。用意再于事件到达预定元素之前捕获它。
DOM流事件
DOM2级事件:规定事件流包括三个阶段: 事件捕获阶段,处于目标阶段 和事件冒泡阶段。
事件捕获: 为截获事件提供机会。 然后是实际的目标接收到事件。最后一个阶段冒泡阶段,可以在这个阶段对事件做出响应
事件处理程序
响应某个事件的函数就叫做事件处理程序(事件侦听器)。
HTML事件处理程序
<input type="button" value="click Me!" onclick="alert(event.type)">
通过event变量,可以直接访问事件对象。不用定义也不用从函数的参数列表中读取。
在这个函数的内部,this等于事件目标的元素。
<input type="button" value="click Me!" onclick="alert(this.type)">
HTML事件处理程序的缺点:
1、存在时差问题。用户再页面还没有解析事件处理程序的函数之前点击了按钮。会引发错误。
2、作用域链再不同浏览器中会导致不同结果。JS引擎遵循的标识符解析规则略有差异,很可能再访问非限定对象成员时出错。
3、需要修改事件时。需要修改HTML和JS俩处。
DOM0级事件处理程序
将一个函数赋值给一个事件处理程序属性。优势在于简单。具有跨浏览器的优势。
每个元素都有自己的事件处理程序属性,将属性的值设为一个函数,就可以指定事件处理程序,程序中this引用当前元素。通过this访问元素的任何属性和方法,以这种方式会在事件的冒泡阶段被处理。
var btn = document.getElementById("myBtn"); btn.onclick = function() { alert(this.id); //“myBtn” }
DOM2级事件处理程序
DOM2级定义了俩个方法用于处理指定和删除事件处理程序的操作:addEventListener()和 removeEventListener(): 接受三个参数 要处理的事件名、作为事件处理程序的函数、布尔值(true: 捕获阶段调用事件处理程序,false: 冒泡阶段调用)。
2级事件处理程序好处在于可以绑定多个事件处理程序。
var btn = document.getElementById("myBtn"); btn.addEventListener("click", function() { alert(this.id); }, false); btn.addEventListener("click", function() { alert(this.tagName); }, false);
removeEventListener,事件处理程序必须与传入addEvenListener()中的相同。
var btn = document.getElementById("myBtn"); var hander = function() { alert(this.id); } btn.addEventListener("click", hander, false); btn.removeListener("click", hander, false)
把事件处理程序添加到冒泡阶段,可以最大限度的兼容性浏览器。需要事件到达目标之前截获的时候才添加事件捕获。
IE 事件处理程序
IE浏览器使用attachEvent()和detachEvent()接受俩个参数: 事件处理程序名称 、事件处理函数。IE的事件处理程序不是以添加他们的顺序执行,以相反的顺序被触发。
var btn = document.getElementById("myBtn"); var hander = function() { alert(this.id); } btn.attachEvent("onclick", hander, false); btn.detachEvent("onclick", hander, false)
一个跨浏览器的事件处理程序
var Eventil = { addHandler: function(element, type, handler) { if(element.addEventListener) { element.addEventlistener(type, handler, false); }else if(element.attacthEvent) { element.attacthEvent("on" + type, handler); }else{ element["on" + type] = handler; } }, removeHandler: function(element, type, handler) { if(element.removeEvent) { element.removeEvent(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(this.id); } EventUtil.addEventer(btn, "click', hander);
事件对象
在触发DOM上的某个事件时,会产生一个事件对象event.这个对象中包含着所有事件有关的信息。
var btn = document.getElementById("myBtn"); btn.addEventListener(click, function(event) { alert(event.type); }, false);
再事件处理程序内部,对象this始终等于currentTarget(事件处理程序当前正在处理的那个元素)的值,而target则只包含事件的实际目标。
var btn = document.getElementById("myBtn"); btn.onclick = function(event) { console.log(event.currentTarget == this); //true console.log(event.target === this); //true }
如果事件处理程序存在于父节点中这些值就不一样了
document.body.onclick = function(event) { console.log(event.currentTarget === document.body); //true console.log(this === document.body); //this和currentTarget都等于document.body 因为事件是注册再这个元素上的 console.log(event.target === document.getElementById("myBtn")); // 真正的事件目标是mybtn }
preventDefault(): 用于阻止特定事件的默认行为。只有canselable(是否可以取消默认事件)属性设置为true的事件,才可以使用preventDefault()。
stopPropagation(): 用于立即停止事件再DOM传播。
var link = document.getElementById("links"); link.onclick = function(event) { event.preventDefault(); event.stopPropagation(); }; document.body.onclick = function(event) { console.log("Body Clicked") }
event对象只存在于处理程序执行期间,事件处理程序执行完毕 立即被销毁。
IE中的事件对象
DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。
var btn = document.getElementById("myBtn"); btn.onclick = function() { var event = window.event; console.log(event.type); //click }
事件处理程序使用attachEvent()添加的,就会有一个event对象、作为参数被传入事件处理函数。
cancelBUbble: 默认值为false,设置为true可以取消事件冒泡。
returnValue: 默认值为true,设置为false可以取消事件默认行为。
srcElement: 事件的目标
type: 被触发的事件类型
跨浏览器的事件对象
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] = handler;
}
},
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;
}
},
getEvent: function(event) {
return event ? event : window.event;
},
getTarget: function(event) {
return event.target || event.srcElement;
},
prevenrDefault: function(event) {
if(event.preventDefault) {
event.preventDefault();
}else {
event.returnValue = false;
}
},
stopPropagation: function(event) {
if(event.stopPropagation) {
event.stopPropagation();
}else {
event.cancelBubble = true;
}
}
};
事件类型
1、Load事件
页面完全加载后(包括图像,JS文件,CSS文件等外部资源).就会触发window上面的load事件。
有俩种定义onload事件处理程序的方法
第一种使用JS指定事件处理程序
EventUtil.addHandler(window,"load", function(event) { console.log("loaded"); });
第二种为<body>元素添加一个onload特性。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Computed Styles Example</title> </head> <body onload="console.log("loading")"> </body> </html>
2、鼠标与滚轮事件
客户区坐标位置(页面坐标位置)
clientX和clientY等于pageX和pageY
屏幕坐标位置
鼠标事件发生时。不仅会有相对浏览器的窗口位置,还有一个相对于整个电脑屏幕的位置。
screenX和screenY属性相对整个屏幕的坐标。
3、鼠标按钮
对于mousedowm和mouseup ,在event对象中存在一个button属性,表示按下或释放。
button可能的值: 0:主鼠标按钮, 1:中间鼠标按钮 , 2 次鼠标按钮
event对象中detail属性
detail属性对于鼠标事件,包含一个数值,表示再给定位置上发生了多少单击。
鼠标滚轮事件
mousewheel:通过鼠标滚轮与页面交互。再垂直方向滚动页面时,就会触发。最终冒泡到document(IE8)对象或window对象。
wheelDelta属性: 鼠标滚轮向前滚动wheelDelta是120的倍数,向后滚是-120的倍数。多数情况只要指定滚动的方向,即检测wheelDelta的正负号。
内存和性能
事件委托:利用事件冒泡,只指定一个事件处理程序,管理一个类型的事件。