事件
事件流
- 事件流描述的是从页面中接收事件的顺序
事件冒泡
- IE的事件流叫做事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点
事件捕获
- 事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件,事件捕获的用意在于在事件到达预定目标之前捕获它。
DOM事件流
- DOM2级事件规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段
事件处理程序
HTML事件处理程序
-
某个元素支持的每种事件都可以使用一个与相应事件处理程序同名的HTML特性来指定,这个特性的值应该是能够执行的JavaScript代码
<input type="button" value="Click Me" onclick="alert('Clicked')">
DOM0级事件处理程序
-
每个元素,包括window和document都有自己的事件处理程序属性,这些属性通常全部小写
var btn=document.getElementById("myBtn"); btn.onclick=function(){ alert("Clicked"); };
DOM2级事件处理程序
-
DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作,addEventListener()和removeEventListener()。所有DOM节点中都包含这两个方法,并且它们都接受3个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序,如果是false,表示在冒泡阶段调用事件处理程序
var btn=document.getElementById("myBtn"); btn.addEventListener("click",function()){ alert(this.id); },false); btn.addEventListener("click",function(){ alert("Hello world!"); },false)
- 通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,移除时传入的参数与添加处理程序时使用的参数相同,这也意味着通过addEventListener()来添加的匿名函数将无法移除
IE事件处理程序
- IE实现了与DOM中蕾西的两个方法,attachEvent()和detachEvent()。这两个方法接收相同的两个参数,事件处理程序和事件处理程序函数
跨浏览器的事件处理程序
- 要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段
- 第一个要创建的方法是addHandler(),它的职责是视情况分别使用DOM0级方法,DOM2级方法或IE方法来添加时间,这个方法属于一个名叫EventUtil的对象。addHandler()方法接收3个参数:要操作的元素、事件名称和事件处理程序函数
- 与addHandler()对应的方法是removeHandler()它也接收相同的参数,这个方法的职责是移除之前添加的事件处理程序,无论事件处理程序时采取什么方式添加到元素中的,如果其他方法无效,默认采用DOM0级方法
事件对象
DOM中的事件对象
- 兼容DOM的浏览器会将一个event对象传入到事件处理程序中,无论指定事件处理程序使用什么方法,都会传入event对象
IE中的事件对象
事件类型
-
DOM3级事件规定以下几类事件
- UI事件,当用户与页面上的元素交互时触发
- 焦点事件,当元素获得或失去焦点时触发
- 鼠标事件,当用户通过鼠标在页面上执行操作时触发
- 滚轮事件,当使用鼠标滚轮时触发
- 文本事件,当在文档中输入文本时触发
- 键盘事件,当用户通过键盘在页面上执行操作时触发
- 合成事件,当为IME输入字符时触发
- 变动事件,当底层DOM结构发生变化时触发
- 变动名称事件,当元素或属性名变动时触发,已废弃
UI事件
-
UI事件指的是那些不一定与用户操作有关的事件
- DOMActivate,表示元素已经被用户操作,通过鼠标或键盘激活
- load,当页面完全加载后在window上面触发,当所有的框架都加载完毕时在框架集上面触发,当图像加载完毕时在<img>元素上触发,或者嵌入的内容加载完毕时在<object>元素上面触发
- unload,当页面完全卸载后在window上面触发,当左右框架都卸载后在框架上面触发,或者当嵌入的内容卸载完毕后在<object>元素上面触发
- abort,在用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上面触发
- error,当大声在JavaScript错误时在window上面触发,当无法加载图像时在<img>元素上面触发,当无法加载嵌入内容时,在<object>元素上面触发,或者当有一个或多个框架无法加载时在框架集上面触发
- select,当用户选择文本框中一个或多个字符时触发
- resize,当窗口或框架的大小变化时在window或框架上面触发
- scroll,当用户滚动带滚动条的元素中的内容时,在该元素上面触发,<body>元素汇总包含所加载页面的滚动条
焦点事件
-
焦点事件会在页面元素获得或失去焦点时触发
- blur,在元素失去焦点时触发,事件不会冒泡,所有浏览器都支持
- DOMFocusIn,在元素获得焦点时触发,这个时间与HTML事件focus等价,但是冒泡,只有Opera支持这个事件,DOM3级事件废弃了DOMFocusIn,选择了focusin
- DOMFocusOut,在元素失去焦点时触发,这个事件是HTML事件blur的通用版本,室友Opera支持这个事件,DOM3级事件废弃了DOMFocusOut,选择了focusout
- focus,在元素获得焦点时触发,这个事件不会冒泡,所有浏览器都支持它
- focusin,在元素获得焦点时触发,这个事件与HTML事件focus等价,但它冒泡,支持这个事件的浏览器有IE5.5+、Safari5.1+、Opera11.5+和Chrome
- focusout,在元素失去焦点时触发,这个事件是HTML事件blur的通用版本,支持这个事件的浏览器有IE5.5+、Safari5.1+、Opera11.5+和Chrome
-
当焦点从页面中的一个元素移动到另一个元素
- focusout在失去焦点的元素上触发
- focusin在获得焦点的元素上触发
- blur在失去焦点的元素上触发
- DOMFocusOut在失去焦点的元素上触发
- focus在获得焦点的元素上触发
- DOMFocusIn在获得焦点的元素上触发
鼠标与滚轮事件
-
鼠标事件是Web开发中最常用的一类事件
- click,在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。这一点对确保易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
- dblclick,在用户双击主鼠标按钮(一般是左边的按钮)时触发。从技术上说,这个事件并不是 DOM2 级事件规范中规定的,但鉴于它得到了广泛支持,所以 DOM3 级事件将其纳入了标准。
- mousedown,在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
- mouseenter,在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。IE、Firefox 9+和 Opera 支持这个事件。
- mouseleave,在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。IE、Firefox 9+和 Opera 支持这个事件。
- mousemove,当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
- mouseout,在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
- mouseover,在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
- mouseup,在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。
-
发生位置
- 客户区坐标位置,clientX和clientY
- 页面坐标位置,pageX和pageY
- 屏幕坐标位置,screenX和screenY
-
修改键
- 规定4个属性,shiftKey、ctrlKey、altKey和metaKey
- 这些属性中包含的都是布尔值,如果相应的键被按下,则值为true,否则为false
-
鼠标按钮
- 0,表示没有按下按钮
- 1,表示按下了主鼠标按钮
- 2,表示按下了次鼠标按钮
- 3,表示同时按下了主、次鼠标按钮
- 4,表示按下了中间的鼠标按钮
- 5,表示同时按下了主鼠标按钮和中间的鼠标按钮
- 6,表示同时按下了次鼠标按钮和中间的鼠标按钮
- 7,表示同时按下了三个鼠标按钮
-
更多的事件信息
- altLeft,布尔值,表示是否按下了Alt键,如果altLeft值为true,则altKey值也为true
- ctrlLeft,布尔值,表示是否按下了Ctrl键,如果ctrlLeft值为true,则ctrlKey值为true
- offsetX,光标相对于目标元素边界的x坐标
- offsetY,光标相对于目标元素边界的y坐标
- shiftLeft,布尔值,表示是否按下了Shift键,如果shiftLeft值为true,则shiftKey值为true
-
鼠标滚轮事件
- 与mousewheel事件对应的event对象除包含鼠标事件的所有标准信息外,还包含一个特殊的wheelDelta属性,当用户向前滚动鼠标滚轮时,wheelDelta是120的倍数,当用户向后滚动鼠标滚轮时,wheelDelta是-120的倍数
-
触摸设备
- 不支持dbclick事件,双击浏览器窗口会放大画面,而且没有办法改变该行为
- 轻击可单击元素会触发mousemove事件,如果此操作会导致内容变化,将不再有其他事件发生,如果屏幕没有因此变化,那么会一次发生mousedown、mouseup和click事件,轻击不可单击的元素不会触发任何事件,可单击的元素指的是那些单击可产生默认操作得元素,或者那些已经被指定了onclick事件处理程序的元素
- mousemove事件也会触发mouseover和mouseout事件
- 两个手指放在屏幕上且页面随手指移动而滚动时会触发mousewheel和scroll事件
键盘与文本事件
-
3个键盘事件
- keydown,当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件
- keypress,当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件
- keyup,当用户释放键盘上的键时触发
- 键码
-
textInput事件,event对象上一个属性,叫inputMethod,表示把文本输入到文本框中的方式
- 0,表示浏览器不确定是怎么输入的
- 1,表示是使用键盘输入的
- 2,表示文本是粘贴进来的
- 3,表示文本是拖放进来的
- 4,表示文本是使用IME输入的
- 5,表示文本是通过在表单中选择某一项输入的
- 6,表示文本是通过手写输入的
- 7,表示文本是通过语音输入的
- 8,表示文本是通过几种方法组合输入的
- 9,表示文本是通过脚本输入的
复合事件
-
用于处理IME的输入序列
- compositionstart,在IME的文本复合系统打开时触发,表示要开始输入了
- compositionupdate,在向输入字段中插入新字符时触发
- compositionend,在IME的文本复合系统关闭时触发,表示返回正常键盘输入状态
-
复合事件与文本事件在很多方面都很相似,在触发复合事件时,目标是接收文本的输入字段,但它比文本事件的事件对象多一个属性data
- 如果compositionstart事件发生时访问,包含正在编辑的文本
- 如果在compositionupdate事件发生时访问,包含正插入的新字符
- 如果在compositionend事件发生时访问,包含此次输入会话中插入的所有字符
变动事件
-
在DOM中的某一部分发生变化时给出提示,变动事件是为XML或HTML DOM设计的,并不特定某种语言
- DOMSubtreeModified,在DOM结构中发生任何变化时触发,这个事件在其他任何事件触发后都会触发
- DOMNodeInserted,在一个节点作为子节点被插入到另一个节点中时触发
- DOMNodeRemoved,在节点从其父元素中被移除时触发
- DOMNodeInsertedIntoDocument,在一个节点被直接插入文档或通过子树间接插入文档之后触发
- DOMNodeRemovedFromDocument,在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发
- DOMAttrModified,在特性被修改之后触发
- DOMCharacterDataModified,在文本节点的值发生变化时触发
-
删除节点
- 在使用removeChild()或replaceChild()从DOM中删除节点时,首先会触发DOMNodeRemoved事件
- 紧随其后触发的是DOMSubtreeModified事件,这个事件的目标是被移除节点的父节点,此时的event对象也不会提供与事件相关的其他信息
-
插入节点
- 在使用appendChild()、replaceChild()或insertBefore()向DOM中插入节点时,首先会触发DOMNodeInserted事件,这个事件的目标是被插入的节点
- 紧接着会在新插入的节点上面触发DOMNodeInsertedIntDocument事件,这个事件不冒泡,因此必须在插入节点之前为它添加这个事件处理程序
- 最后一个触发的是DOMSubtreeModified,触发于新插入节点的父节点
HTML5事件
- contextmenu事件,用以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单
- beforeunload事件,为了让开发人员有可能在页面卸载前阻止这一个操作,这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面
-
readystatechange事件,目的是提供与文档或元素加载状态有关的信息,但这个事件的行为有时候也难预料,支持readystatechange事件的每个对象都有一个readyState属性
- uninitialized,对象存在但尚未初始化
- loading,对象正在加载数据
- loaded,对象加载数据完成
- interactive,可以操作对象了,但还没有完全加载
- complete,对象已经加载完毕
- pageshow事件,在页面显示时触发,无论该页面是否来自bfcache,在重新加载的页面中,pageshow会在load事件触发后触发,而对于bfcache中的页面,pageshow会在页面状态完全恢复的那一刻触发
- pagehide事件,在浏览器卸载页面的时候触发,而且是在unload事件之前触发,与pageshow事件一样,pagehide在document上面触发,但其事件处理程序必须要添加到window对象
- hashchange事件,在URL参数列表发生变化时,通知开发人员。之所以新增这个事件,是因为在Ajax应用中,开发人员经常要利用URL参数列表来保存状态或导航信息
设备事件
- orientationchange事件,以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式。0表示肖像模式,90表示向左旋转的横向模式,-90表示向右旋转的横向模式
-
MozOrientation事件,当设备的加速计检测到设备方向改变时,就会触发这个事件
- event对象包含三个属性,x、y、z,这几个属性的值都介于1到-1之间,表示不同坐标轴上的方向。在静止状态下,x值为0,y值为0,z值为1。如果设备向右倾斜,x值会减小;反之向左倾斜,x值会增大。类似的,如果设备向远离用户的方向倾斜,y值会减小,向接近用户的方向倾斜,y值会增大。z轴检测垂直加速度,1表示静止不动,在设备移动时,值会减小,失重状态下值为0
- deviceorientation事件与Mozorientation事件类似,它也是在加速计检测到设备方向变化时,在window对象上触发,而且具有与MozOrientation事件相同的支持限制。不过deviceorientation事件的意图是告诉开发人员设备在空间中朝向哪儿,而不是如何移动
-
触发deviceorientation事件时,事件对象中包含着每个轴相对于设备静止状态下发生变化的信息,包含5个属性
- alpha,在围绕z轴旋转时(左右旋转),y轴的度数差,是一个介于0到360之间的浮点数
- beta,在围绕x轴旋转时(前后旋转),z轴的度数差,是一个介于-180到180度之间的浮点数
- gamma,在围绕y轴旋转时(扭转设备),z轴的度数差,是一个介于-90到90之间的浮点数
- absolute,布尔值,表示设备是否返回一个绝对值
- compassCalibrated,布尔值,表示设备的指南针是否校准过
-
devicemotion事件,告诉开发人员设备什么时候移动,而不仅仅是设备方向如何改变
- acceleration,一个包含x、y和z属性的对象,在不考虑重力的情况下,说明每个方向上的加速度
- accelerationIncludingGravuty,一个包含x、y和z属性的对象,在考虑z轴自然重力加速度的情况下,说明每个方向上的加速度
- interval,以毫秒表示的时间值,必须在另一个devicemotion事件触发前传入,这个值在每个事件中应该是一个常量
- rotationRate,一个包含表示方向的alpha、beta和gamma属性的对象
触摸与手势事件
-
触摸事件
- touchstart,当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
- touchmove,当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用 preventDefault()可以阻止滚动。
- touchend,当手指从屏幕上移开时触发。
- touchcancel :当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。
-
除了常见的DOM属性之外,触摸事件还包含三个用于跟踪触摸的属性
- touches,表示当前跟踪的触摸操作的 Touch 对象的数组。
- targetTouchs,特定于事件目标的 Touch 对象的数组。
- changeTouches,表示自上次触摸以来发生了什么改变的 Touch 对象的数组。
-
每个Touch对象包含下列属性
- clientX,触摸目标在视口中的 x 坐标。
- clientY,触摸目标在视口中的 y 坐标。
- identifier,标识触摸的唯一 ID。
- pageX,触摸目标在页面中的 x 坐标。
- pageY,触摸目标在页面中的 y 坐标。
- screenX,触摸目标在屏幕中的 x 坐标。
- screenY,触摸目标在屏幕中的 y 坐标。
- target,触摸的 DOM 节点目标。
-
手势事件
- gesturestart,当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
- gesturechange,当触摸屏幕的任何一个手指的位置发生变化时触发。
- gestureend,当任何一个手指从屏幕上面移开时触发。
内存和性能
事件委托
-
对"事件处理程序过多"问题的解决方案,就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
var item1 = document.getElementById("goSomewhere"); var item2 = document.getElementById("doSomething"); var item3 = document.getElementById("sayHi"); EventUtil.addHandler(item1, "click", function(event){ location.href = "http://www.wrox.com"; }); EventUtil.addHandler(item2, "click", function(event){ document.title = "I changed the document's title"; }); EventUtil.addHandler(item3, "click", function(event){ alert("hi"); });
模拟事件
DOM中的事件模拟
-
可以在document对象上使用createEvent()方法创建event对象,这个方法就是接收一个参数,即表示要创建的事件类型的字符串
- UIEvents,一般化的UI事件,鼠标事件和键盘事件都继承自UI事件,DOM3级中是UIEvent
- MouseEvents,一般化的鼠标事件,DOM3级中是MouseEvent
- MutationEvents,一般化的DOM变动事件,DOM3级中是MutationEvent
- HTMLEvents,一般化的HTML事件,没有对应的DOM3级事件
-
模拟鼠标事件
- type(字符串),表示要触发的事件类型,例如 "click" 。
- bubbles(布尔值),表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为true 。
- cancelable(布尔值),表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设置为 true 。
- view(AbstractView),与事件关联的视图。这个参数几乎总是要设置为 document.defaultView 。
- detail(整数),与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为 0 。
- screenX(整数),事件相对于屏幕的 X 坐标。
- screenY(整数),事件相对于屏幕的 Y 坐标。
- clientX(整数),事件相对于视口的 X 坐标。
- clientY(整数),事件想对于视口的 Y 坐标。
- ctrlKey(布尔值),表示是否按下了 Ctrl 键。默认值为 false 。
- altKey(布尔值),表示是否按下了 Alt 键。默认值为 false 。
- shiftKey(布尔值),表示是否按下了 Shift 键。默认值为 false 。
- metaKey(布尔值),表示是否按下了 Meta 键。默认值为 false 。
- button(整数),表示按下了哪一个鼠标键。默认值为 0 。
- relatedTarget(对象),表示与事件相关的对象。这个参数只在模拟 mouseover 或 mouseout时使用。
var btn = document.getElementById("myBtn"); //创建事件对象 var event = document.createEvent("MouseEvents"); //初始化事件对象 event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); //触发事件 btn.dispatchEvent(event);
-
模拟键盘事件
- type(字符串),表示要触发的事件类型,如 "keydown" 。
- bubbles(布尔值),表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为 true 。
- cancelable(布尔值),表示事件是否可以取消。为精确模拟鼠标事件,应该设置为 true 。
- view(AbstractView) ,与事件关联的视图。这个参数几乎总是要设置document.defaultView 。
- key(布尔值),表示按下的键的键码。
- location(整数),表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
- modifiers(字符串),空格分隔的修改键列表,如 "Shift" 。
- repeat(整数),在一行中按了这个键多少次。
var textbox = document.getElementById("myTextbox"), event; //以 DOM3 级方式创建事件对象 if (document.implementation.hasFeature("KeyboardEvents", "3.0")){ event = document.createEvent("KeyboardEvent"); //初始化事件对象 event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, "Shift", 0); } //触发事件 textbox.dispatchEvent(event);
-
在Firefox中,调用createEvent()并传入"KeyEvents"就可以创建一个键盘事件,返回的事件对象会包含一个initKeyEvent()方法,接收10个参数
- type(字符串),表示要触发的事件类型,如 "keydown" 。
- bubbles(布尔值),表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为 true 。
- cancelable(布尔值),表示事件是否可以取消。为精确模拟鼠标事件,应该设置为 true 。
- view(AbstractView) ,与事件关联的视图。这个参数几乎总是要设置为 document.default-View 。
- ctrlKey(布尔值),表示是否按下了 Ctrl 键。默认值为 false 。
- altKey(布尔值),表示是否按下了 Alt 键。默认值为 false 。
- shiftKey(布尔值),表示是否按下了 Shift 键。默认值为 false 。
- metaKey(布尔值),表示是否按下了 Meta 键。默认值为 false 。
- keyCode(整数),被按下或释放的键的键码。这个参数对 keydown 和 keyup 事件有用,默认值为 0 。
- charCode(整数),通过按键生成的字符的 ASCII 编码。这个参数对 keypress 事件有用,默认值为 0 。
//只适用于 Firefox var textbox = document.getElementById("myTextbox") // 创建事件对象 var event = document.createEvent("KeyEvents"); // 初始化事件对象 event.initKeyEvent("keypress", true, true, document.defaultView, false, false, false, false, 65, 65); //触发事件 textbox.dispatchEvent(event);
-
要创建新的自定义事件,可以调用createEvent("CustomEvent"),接收4个参数
- type(字符串),触发的事件类型,例如 "keydown" 。
- bubbles(布尔值),表示事件是否应该冒泡。
- cancelable(布尔值),表示事件是否可以取消。
- detail(对象),任意值,保存在 event 对象的 detail 属性中
var div = document.getElementById("myDiv"), event; EventUtil.addHandler(div, "myevent", function(event){ alert("DIV: " + event.detail); }); EventUtil.addHandler(document, "myevent", function(event){ alert("DOCUMENT: " + event.detail); }); if (document.implementation.hasFeature("CustomEvents", "3.0")){ event = document.createEvent("CustomEvent"); event.initCustomEvent("myevent", true, false, "Hello world!"); div.dispatchEvent(event); }
IE中的事件模拟
-
模拟一个按钮触发click事件过程
var btn = document.getElementById("myBtn"); //创建事件对象 var event = document.createEventObject(); //初始化事件对象 event.screenX = 100; event.screenY = 0; event.clientX = 0; event.clientY = 0; event.ctrlKey = false; event.altKey = false; event.shiftKey = false; event.button = 0; //触发事件 btn.fireEvent("onclick", event);
-
模拟keypress事件
var textbox = document.getElementById("myTextbox"); //创建事件对象 var event = document.createEventObject(); //初始化事件对象 event.altKey = false; event.ctrlKey = false; event.shiftKey = false; event.keyCode = 65; //触发事件 textbox.fireEvent("onkeypress", event);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。