JavaScript笔记-事件
《JavaScript高级程序设计》事件部分笔记。
事件流
事件流描述的是页面的元素接收事件的顺序。
当时IE4.0提出了冒泡模型,而Netscape4.0提出的是捕获模型。
比如这样的一个页面:
1 |
|
事件冒泡是这样的:
- 所有浏览器都支持
- 会一直冒泡到window对象(图片只画到了document对象)
- 不是所有事件都会冒泡
事件捕获是这样的:
- DOM2级事件规范从document对象开始传播,但是浏览器实现都是从window对象开始传播
- IE9、Safari、Chrome、Firefox 和 Opera 9.5 及更高版本
DOM2事件流则是两种的整合:
- 有三个阶段:1.事件捕获阶段 2.目标阶段 3.事件冒泡阶段
- DOM2级事件规范要求捕获阶段目标不会收到事件。也就是说,例子中,div被点击了,首先是捕获阶段document > html > body就结束了。但是目前的浏览器实现,会在捕获阶段也让目标收到事件,也就是捕获阶段变为:document > html > body > div。
- IE9、Safari、Chrome、Firefox 和 Opera 9.5 及更高版本支持
事件处理程序
HTML事件处理程序
使用HTML特性指定事件的处理代码。不推荐使用了。
1 | <input type="button" value="Click Me" onclick="alert("Clicked")" /> |
- 可以使用一些特殊变量:
this
,event
DOM0级事件处理程序
DOM0级的特点是简单粗暴。每个元素(包括window和document)都有自己的事件处理程序属性,一般命名是在事件名称前加上on,比如onclick
。
1 | var btn = document.getElementById("myBtn"); |
DOM2级事件处理程序
DOM0级事件处理程序虽然简单,但是有明显缺点,就是一个元素只能绑定一个事件处理函数。所以DOM2级规范定义了两个方法:addEventListener()
和removeEventListener()
。
addEventListener(type, listener[, useCapture])
有三个参数:
type
事件名称listener
事件处理函数useCapture
是否在捕获阶段调用处理程序。ture表示在捕获阶段,false表示在冒泡阶段。
1 | var btn = document.getElementById("myBtn"); |
removeEventListener()
和addEventListener()
拥有一样的方法签名。只是指定的listener
是你想要删除的事件处理函数的引用。
事件对象
在DOM上触发事件时,会产生一个event对象。通过这个对象我们可以知道发生了什么事件,目标是谁等等。不同的事件产生的event对象的属性是不一样的。共有的属性有:
属性/方法 | 类型 | 读写 | 说明 |
---|---|---|---|
bubbles | Boolean | 只读 | 表明是否冒泡 |
cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 事件处理程序绑定的元素 |
defaultPrevented | Boolean | 只读 | 为true表示已经调用了preventDefault()(DOM3级事件中新增) |
detail | Integer | 只读 | 与事件相关的细节信息 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件中新增) |
stopPropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为true表示事件是浏览器生成的。为false表 示事件是由开发人员通过JavaScript创建的(DOM3级事件中新增) |
type | String | 只读 | 被触发的事件的类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的window对象 |
在事件处理函数内部,this
始终等于currentTarget
的值。而target
始终指向触发事件的对象。
事件实验:http://jsbin.com/zucutidozi/2/edit?html,js,output
只有在事件处理程序执行期间,event 对象才会存在;一旦事件处理程序执行完 成,event 对象就会被销毁。
事件类型
DOM3级事件规定了一下几类事件:
- UI事件,当用户与页面上的元素交互时触发;
- 焦点事件,当元素获得或失去焦点时触发;
- 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
- 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
- 文本事件,当在文档中输入文本时触发;
- 键盘事件,当用户通过键盘在页面上执行操作时触发;
- 合成事件,当为 IME(Input Method Editor,输入法编辑器)输入字符时触发;
- 变动(mutation)事件,当底层 DOM 结构发生变化时触发。
- 变动名称事件,当元素或属性名变动时触发。此类事件已经被废弃,没有任何浏览器实现它们。
全部事件的列表可以参考官方文档:Event reference | MDN
事件涉及到的细节很多,比如每个事件是否是冒泡的,是否有默认行为,是否可以取消默认行为,是否会非常频繁的触发等等等等,所以最好是多查官方文档。
UI事件
load
- 页面完全加载后在window上触发
- 所有框架都加载完成后在框架集上触发
- 图片加载完成后在img元素上触发
- 嵌入内容加载完毕后在object元素上触发
unload
- 页面完全卸载后在window上触发(用户切换页面的时候发生)
- 所有框架都卸载后在框架集上触发
- 嵌入内容卸载后在object元素上触发
abort
在用户停止下载过程时,如果嵌入的内容没有加载完,则在object元素上面触发error
- 当发生 JavaScript 错误时在 window 上面触发
- 当无法加载图像时在img元素上面触 发
- 当无法加载嵌入内容时在object元素上面触发
- 当有一或多个框架无法加载时在框架集上面触发
select
当用户选择文本框(input或texterea)中的一或多个字符时触发- 是否冒泡:是
- 是否可以取消:否
- 目标:Element
- 默认行为:无
resize
当窗口或框架的大小变化时在window或框架上面触发- 是否冒泡:否
- 是否可以取消:否
- 目标:defaultView
- 默认行为:无
- 变化1像素就会触发,所以会非常频繁的触发,所以事件处理程序不能有非常复杂的逻辑(写法见官方文档)
scroll
当用户滚动带滚动条的元素中的内容时,在该元素上面触发。body元素中包含所加载页面的滚动条- 是否冒泡:普通元素上触发不会冒泡,但是如果是在document上触发,则会冒泡到window
- 是否可以取消:否
- 默认行为:无
- 目标:defaultView, Document, Element
- 如果是整个页面滚动,也就是document滚动,可以通过
document.documentElement
的scrollTop
和scrollLeft
属性获取滚动的距离 - 如果是具体的元素滚动,则可以获取具体元素的
scrollTop
和scrollLeft
属性获取滚动的距离
焦点事件
focus
在元素获得焦点时触发。不冒泡blur
在元素失去焦点时触发。不冒泡focusin
在元素获得焦点时触发。冒泡focusout
在元素失去焦点时触发。冒泡
在焦点从一个元素到另外一个元素上时,事件触发顺序如下:
- focusout 在失去焦点的元素上触发;
- focusin 在获得焦点的元素上触发;
- blur 在失去焦点的元素上触发;
- focus 在获得焦点的元素上触发;
focusin/focusout
相较于focus/blur
,有两个优点:
focusin/focusout
会冒泡,focus/blur
不会focusin/focusout
的FocusEvent.relatedTarget
字段会设置为前一个聚焦的元素/下一个聚焦的元素
鼠标与滚轮事件
click
按下鼠标左键或者回车键触发dbclick
双击鼠标左键触发mousedown
按键任意鼠标按键触发mouseup
释放鼠标按键时触发mouseenter
在鼠标首次移动到元素范围内触发。不冒泡mouseleave
在鼠标移动到元数据范围外触发。不冒泡mouseover
在鼠标首次移动到元素范围内触发mouseout
在鼠标从一个元素移动到另外一个元素(可以是子元素)时触发mousemove
当鼠标在元素内移动时重复触发。
除了mouseenter
和mouseleave
都会冒泡,也可以被取消。
只有在同一个元素上触发了mousedown
和mouseup
事件才会触发click
事件。如果其中一个被取消,就不会触发click
事件。只有两次连续触发click
事件才会触发dbclick
事件。mousedown
和mouseup
事件不受其他事件影响。
dbclick
完整的触发顺序如下:
- mousedown
- mouseup
- click
- mousedown
- mouseup
- click
- dblclick
鼠标事件产生的对象是MouseEvent
对象。有一些有用的属性:
属性名 | 说明 |
---|---|
x/y | clientX/clientY的别名 |
clientX/clientY | 以浏览器左上角为原点的鼠标点击位置 |
pageX/pageY | 以页面左上角为原点的鼠标点击位置 |
screenX/screenY | 以屏幕左上角为原点的鼠标点击位置 |
offsetX/offsetY | 以元素左上角为原点的鼠标点击位置 |
shiftKey | 事件发生时,shift键是否按下 |
ctrlKey | 事件发生时,ctrl键是否按下 |
altKey | 事件发生时,alt键是否按下 |
metaKey | 事件发生时,meta键是否按下 |
button | 鼠标按下的按键值,具体见下表 |
buttons | 鼠标按下的所有按键组合值,具体见下表 |
detail | 鼠标在该位置上连续点击几次 |
如果网页没有滚动,那么clientX/clientY
和pageX/pageY
是相等的。
button属性的取值:
- 0 左键
- 1 中键
- 2 右键
- 3 鼠标后退键
- 4 鼠标前进键
但是如果同时按下多个按键怎么办呢?可以用buttons字段:
- 0 没有按键
- 1 左键
- 2 中键
- 4 右键
- 8 鼠标后退键
- 16 鼠标前进键
这些按键的或(|)运算得出button的取值,所以可以通过buttons值算出当前有哪些按键按下。
如果事件是mouseenter
,mouseleave
,mouseover
,mouseout
,MouseEvent.relatedTarge
会设置为响应的相关对象:
事件 | target属性 | relatedTarge属性 |
---|---|---|
mouseenter | 鼠标进入的元素 | 鼠标离开的元素 |
mouseleave | 鼠标离开的元素 | 鼠标进入的元素 |
mouseover | 鼠标进入的元素 | 鼠标离开的元素 |
mouseout | 鼠标离开的元素 | 鼠标进入的元素 |
鼠标事件实验:http://jsbin.com/soqocumeva/1/edit?html,js,output
键盘与文本事件
键盘事件:
keydown
按下任意按键触发,按住不放重复触发keypress
按键字符按键触发,按住不放重复触发keyup
释放按键触发
按下字符按键,事件触发顺序:
- keydown
- keypress
- (文本框发生变化)
- keyup
按下非字符按键,不会触发keypress事件。
键盘事件产生的事件对象是KeyboardEvent
,有用的属性有:
属性名 | 说明 |
---|---|
key | 按键的值,比如a,A,Shift |
code | 按键的名称,比如KeyA,ShiftLeft |
keyCode | 按键码,与ASCII的小写编码相同。用code替代 |
charCode | 字符编码。keypress事件才有。用key替代 |
shiftKey | 事件发生时,shift键是否按下 |
ctrlKey | 事件发生时,ctrl键是否按下 |
altKey | 事件发生时,alt键是否按下 |
metaKey | 事件发生时,meta键是否按下 |
repeat | 是否是按住而触发的 |
可以用String.fromCharCode()
将charCode转为实际的字符。
只有一个文本事件:
textInput
在文本插入可编辑区域前触发
textInput事件产生的是TextEvent
对象
输入法事件
标准名称是复合事件(composition event),处理的是IME相关的事件。
compositionstart
IME打开时触发compositionupdate
在IME中输入新字符时触发compositionend
在IME关闭时触发
产生的事件是CompositionEvent
,包含一个data
字段
compositionstart
时,data
为正在编辑的字段,比如选中的字段compositionupdate
时,data
为最新输入的字符串,比如hao
compositionend
时,data
为最终输入的字符串,比如好
其他有用的事件
contextmenu
在打开上下文菜单时触发。产生的是MouseEvent
。
可以用event.preventDefalut()
取消默认的菜单。
事件实验:http://jsbin.com/soqocumeva/9/edit?html,js,output
参考资料
- DOM0, DOM1, DOM2, DOM3 - CSDN博客
- 《JavaScript高级程序设计》