第13章 事件
JavaScript与HTML之间的交互是通过事件实现的。
事件流:
事件流描述的是从页面中接收事件的顺序。但有意思的是IE和Netscape开发团队居然提出了差不多完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流。
(1)事件冒泡
IE的事件流叫事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
(2)事件捕获
Netscape团队提出的另一种事件流叫做事件捕获。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。
(3)DOM事件流
“DOM2级事件“规定的事件流包括了三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
事件处理程序:
事件就是用户或浏览器自身执行的某个动作。诸如click、load和mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。为事件指定处理程序的方式有好几种。
(1)HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。
事件处理程序函数中有一个局部变量event,也就是事件对象。
(2)DOM0级事件处理程序
通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这样有两个优势,一个是简单,一个是具有跨浏览器的优势。要使用JavaScript指定事件处理程序,首先必须取得一个要操作对象的引用。
每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。
Var btn = document.getElementById(“mybtn”);
btn.onclick = function(){};
使用DOM0级方法指定的事件处理程序被认为是元素的方法。换句话说,程序中的this引用当前元素。会在事件流的冒泡阶段被处理。
(3)DOM2级事件处理程序
“DOM2级事件“定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。所有DOM节点都包含这两个方法,都接收3个参数:要处理的事件名、事件处理程序函数、一个布尔值。最后这个布尔值如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
Var btn = document.getElementById(“mybtn”);
btn.addEventListener(“click”,function(){},false);
通过addEventListener添加的事件处理程序只能使用removeEventListener()来移除,移除时得传入相同的参数,这意味着添加的匿名函数将无法被移除。
(4)IE事件处理程序
IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。
Var btn = document.getElementById(“mybtn”);
btn.attachEvent(“onclick”,function(){});
在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。使用attachEvent()方法的作用域为全局。
(5)跨浏览器的事件处理程序
使用能力检测来进行判断使用哪种处理程序;
事件对象:
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
(1)DOM中的事件对象
event.type可以为click、mouseover、mouseout等;
要阻止特定事件的默认行为,可以使用preventDefault()方法。例如,链接的默认行为就是在被单击时会导航到其href特性指定的URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick事件处理程序可以取消它。
link.onclick = function(event){event.preventDefault();};
只有cancelable属性值设置为true的事件,才可以使用preventDefault()来取消其默认行为。
另外,stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。
(2)IE中的事件对象
与访问DOM中的event对象不同,要访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法。
在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。
在使用attachEvent()添加时,event对象作为参数被传入事件处理程序函数中。
(3)跨浏览器的事件对象
事件类型:
DOM3级事件规定了以下几类事件:
UI事件:当用户与页面上的元素交互时触发;
焦点事件:当元素获得或失去焦点时触发;
鼠标事件:当用户通过鼠标在页面上执行操作时触发;
滚轮事件:当使用鼠标滚轮(或类似设备)时触发;
文本事件:当在文档中输入文本时触发;
键盘事件:当用户通过键盘在页面上执行操作时触发;
合成事件:当为IME(输入法编辑器)输入字段时触发;
变动事件:当底层DOM结构发生变化时触发;
(1)UI事件
load事件:
JavaScript中最常用的一个事件就是load。当页面完全加载后(包括所有图像、JavaScript文件、CSS文件等外部资源),就会触发window上面的load事件。
可以在元素上添加一个onload特性,来指定onload事件处理程序。
图像上面也可以触发load事件。
在DOM出现之前,开发人员经常使用Image对象在客户端预先加载图像。可以像使用元素一样使用Image对象,只不过无法将其添加到DOM树中。
unload事件:
与load事件对应的是unload事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面就会发生unload事件。而利用这个事件最多的情况就是清楚引用,以避免内存泄漏。
resize事件:
当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件。这个事件在window上面触发,因此可以通过JavaScript或者元素中的onresize特性来指定事件处理程序。
scroll事件:
在混杂模式下,可以通过元素的scrollLeft和scrollTop来监控这一变化,而标准模式下,除safari之外的所有浏览器都会通过元素来反映这一变化。
(2)焦点事件
Blur:在元素失去焦点时触发,不冒泡。(还有DOMFocusOut、focusout,但冒泡)
Focus:在元素获得焦点时触发,不冒泡。(还有DOMFocusIn、focusin,但冒泡)
(3)鼠标与滚轮事件
DOM3级事件中定义了9个鼠标事件:
click:在用户单击主鼠标按钮或者按下回车键时触发。
dblclick:在用户双击主鼠标按钮时触发。
Mousedown:在用户按下了任意鼠标按钮时触发。
Mouseenter:在鼠标光标从元素外部首次移动到元素范围内时触发,不冒泡。
mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发,不冒泡。
Mousemove:当鼠标指针在元素内部移动时重复地触发。
Mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。
mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。
mouseup:在用户释放鼠标按钮时触发。
1.客户区坐标位置:
鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX和clientY属性中。注意这个值不包括页面滚动的距离。
2.页面坐标位置:
页面坐标通过事件对象的pageX和pageY属性,能告诉你事件是在页面中的什么位置发生的。IE8及更早版本不支持事件对象的页面坐标,可以通过客户区坐标和滚动信息计算出来。
3.屏幕坐标位置:
鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通过screenX和screenY属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。
4.修改健:
虽然鼠标事件主要是使用鼠标触发的,但是键盘有些键也会影响鼠标的行为。这些键就是Shift、Ctrl、Alt和Meta(windows键)。DOM为此规定了4个属性,表示这些键的状态:shiftKey、ctrlKey、altKey和metaKey,这些属性都是布尔值,按下时为true,否则为false。
5.相关元素:
DOM通过event对象的relatedTarget属性提供了相关元素的值,这个属性只对于mouseover和mouseout事件才包含值,对于其他事件都是null。
6.鼠标按钮:
对于mousedown和mouseup事件来说,在其event对象存在一个button属性,表示按下和释放的按钮。DOM的button属性可能有以下3个值:0表示主鼠标按钮,1表示中间的鼠标按钮,2表示次鼠标按钮。
7.更多事件信息:
“DOM2级事件“规范在event对象中还提供了detail属性,对于鼠标来说,detail包含了一个数值,表示在给定位置上发生了多少次单击。
IE也通过下列属性为鼠标事件提供了更多信息:
offsetX:光标相对于目标元素边界的x坐标。
offsetY:光标相对于目标元素边界的y坐标。
8.鼠标滚轮事件
IE6.0首先实现了mousewheel事件,在垂直方向上(无论向上还是向下),就是触发mousewheel事件。这个事件可以在任何元素上触发,最终会冒泡到document或window对象。
与mousewheel事件对应的event对象还有一个wheelDelta属性,当用户向前滚动时,wheelDelta是120的倍数,当用户向后滚动时,wheelDelta是-120的倍数。
Firefox支持一个名为DOMMouseScroll的类似事件,也是在鼠标滚轮滚动时触发。
9.触摸设备
两个手指放在屏幕上且页面随手指移动而滚动时会触发mousewheel和scroll事件。
10.无障碍性问题
(4)键盘和文本事件
用户在使用键盘时会触发键盘事件,有3个键盘事件,简述如下:
keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
Keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件,按下esc键也会触发此事件。
Keyup:当用户释放键盘上的键时触发。
虽然所有元素都支持以上3个事件,但只有在用户通过文本框输入文本时才最常用到。
当用户按了一下键盘上的字符键时,首先会触发keydown事件,然后紧跟着是keypress事件,最后触发keyup事件。
1.键码
在发生keydown和keyup事件时,event对象的keyCode属性中会包含一个代码,与键盘上一个特定的键对应。
2.字符编码
发生keypress事件意味着按下的键会影响到屏幕中文本的显示。这个事件的event对象包含一个charCode属性,这个值是按下的那个键所代表的字符的ASCII编码。在取得了字符编码之后,就可以使用String.fromCharCode()将其转换成实际的字符。
3.textInput事件
只有一个文本事件:textInput。在文本插入文本框之前会触发textInput事件。
这个与keypress有两点不同,区别之一是任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发textInput事件;区别之二是textInput事件只会在用户按下能够输入实际字符的键时才会被触发,而keypress事件则在按下那些能够影响文本显示的键也会触发(例如退格键)。
该事件对象event中有一个data属性,这个属性的值就是用户输入的字符(而非字符编码)。
(5)复合事件
复合事件是DOM3级事件中新添加的一类事件,用于处理IME的输入序列。IME(输入法编辑器)可以让用户输入在物理键盘上找不到的字符。
(6)变动事件
DOM2级的变动事件能在DOM中的某一部分发生变化时给出提示。
1.删除节点
在使用removeChild()或replaceChild()从DOM中删除节点时,首先会触发DOMNodeRemoved事件。
2.插入节点
在使用appendChild()、replaceChild()或insertBefore()向DOM中插入节点时,首先会触发DOMNodeInserted事件。
(7)HTML5事件
1.contextmenu事件
表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。
2.beforeunload事件
之所以有发生在window对象上的beforeunload事件,是为了让开发人员有可能在页面卸载之前阻止这一操作。
3.DOMContentLoaded事件
如前所述,window的load事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而颇费周折。而DOMContentLoaded事件则在形成完整的DOM树之后就会触发,不理会图像、JavaScript文件、CSS文件或其他资源是否已经下载完毕。
通常这个事件既可以添加事件处理程序,也可以执行其他DOM操作。这个事件始终都会在load事件之前触发。
4.readystatechange事件
IE为DOM文档中的某些部分提供了readystatechange事件,这个事件的目的是提供与文档或元素加载状态有关的信息。支持这个事件的每个对象都有一个readyState属性,可能包含下列5个值中的一个。
uninitialized(未初始化)、loading(正在加载)、loaded(加载完毕)、interactive(交互)、complete(完成)。
另外,