事件就是用户或浏览器自身执行的某种动做,诸如 click、 load 等。而相应某个事件的函数就叫事件处理程序(或事件侦听器),如 onclick、 onload 等。
javascript
事件捕获,与"事件冒泡"相反,从"window"对象开始,沿着 DOM 树逐级向下传播,直到目标元素为止。html
二者能够用下图表示:java
其实二者之间还有一个阶段:处于目标的发生阶段。
数组
添加和删除事件均有两种方法,均为 Element 类型的对象的方法。如下的 "callback" 表示事件处理的回调函数,如function callback(event){ }
,"event" 为内部提供的参数,表示事件对象。须要注意的是,DOM0 级与 DOM 2级 添加事件处理函数会被同时触发,互不干扰。
浏览器
特色是带有"on"字眼。这种方法添加的事件处理函数会在冒泡阶段被处理。这两个方法的优势是使用简单,直接赋值一个函数(或匿名函数或箭头函数);缺点是只能赋值一个函数,后赋值会覆盖前者,因此删除事件也会清除全部。下面以"onclick"为例。
app
ele.onclick = callback
ele.onclick = null
这两个方法的优势是能对同一个元素依次添加多个事件处理函数,也能单独移除某个事件处理函数(必须提供函数的对象),并且能针对冒泡或捕获阶段处理。eventType 表示事件的类型,如 "click" 等,是不带"on"字的;isBubbles 是可选参数,默认为 false ,表示在冒泡阶段处理函数,true 则表示是否在捕获阶段处理函数。下面以"click"为例。
ide
ele.addEventListener(eventType, callback, isCapture?)
ele.removeEventListener(eventType, callback, isCapture?)
浏览器会将 event 对象是传入到事件处理程序中。event 对象有如下属性/方法:函数
属性/方法 | 类型 | 说明 |
---|---|---|
bubbles | Bool | 表示事件是否冒泡。 |
cancelable | Bool | 表示是否能够取消事件的默认行为。 |
currentTarget | Elem | 其事件处理程序当前正在处理事件的那个元素。 |
defaultPrevented | Bool | 为 true 表示已经调用了 preventDefault()。 |
datail | Int | 与事件相关的细节信息。 |
eventPhase | Int | 调用事件程序的阶段: 1-捕获阶段;2-"处于目标";3-冒泡阶段。 |
target | Element | 事件的目标元素对象。 |
trusted | Bool | 为 true 表示事件是浏览器生成的;不然为开发人员经过 JavaScript 建立的。 |
type | Str | 被触发的事件的类型。如, "click" 、 "mouseover" 等。 |
view | AbstractView | 与事件关联的抽象视图。等同于发生事件的 window 对象。 |
preventDefault() | Func | 取消事件的默认行为。如,<a>标签的单击事件就是跳转连接。( cancelable 必须为 true ) |
stopImmediatePropagation() | Func | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用。 |
stopPropagation() | Func | 取消事件的进一步捕获或冒泡。 |
preventDefault()
方法。stopPropagation()
方法。document.addEventListener('load', callback)
。window.addEventListener('resize', callback)
。焦点事件会在页面元素得到或失去焦点时触发。默认状况下,只有input等元素才有焦点事件,但只要给<div>等元素添加tabindex
特性,一样能触发焦点事件,要注意的是,在得到焦点时,某些浏览器可能会为该元素添加边框等样式。post
经过document.hasFocus()
能够判断用户是否与该页面互动(页面未进行任何操做或不在屏幕内显示则返回false)。
性能
经过document.activeElement
属性能够获取当前被聚焦的元素。
鼠标事件继承自 UI Event 。鼠标事件包括左键、右键、滚轮。单击指代的是左键点击一下,双击则左键连续点击两下。全部元素都支持鼠标事件。
除了mouseenter
和mouseleave
,全部鼠标事件都冒泡。
只有在同一个元素上相继触发mousedown
和mouseup
事件,才会触发click
事件;相似的,只有触发两次click
事件才会触发一次dblclick
事件。
事件列表以下:
e.preventDefault()
能够阻止"上下文菜单"的打开,而后经过获取鼠标位置,在指定位置显示自制的"菜单"。也能够用mousedown
代替。鼠标触发的事件,其event
对象有几个属性是值得关注的:
属性 | 值类型 | 使用场景 | 说明 |
---|---|---|---|
clientX | Integer | * |
触发该事件时,鼠标光标相对于浏览器视口的X轴位置。 |
clientY | Integer | * |
触发该事件时,鼠标光标相对于浏览器视口的Y轴位置。 |
pageX | Integer | 页面有滚动条 | 触发该事件时,鼠标光标相对于浏览器页面(非视口)的X轴位置。 |
pageY | Integer | 页面有滚动条 | 触发该事件时,鼠标光标相对于浏览器页面(非视口)的Y轴位置。 |
shiftKey | Boolean | 键盘组合鼠标 | 当按下"shift"键的同时触发鼠标事件,该属性值为true,不然为false。 |
ctrlKey | Boolean | 键盘组合鼠标 | 当按下"ctrl"键的同时触发鼠标事件,该属性值为true,不然为false。 |
altKey | Boolean | 键盘组合鼠标 | 当按下"alt"键的同时触发鼠标事件,该属性值为true,不然为false。 |
metaKey | Boolean | 键盘组合鼠标 | 当按下"meta"键的同时触发鼠标事件,该属性值为true,不然为false。 |
relatedTarget | Element | 与两个元素有关的事件 | mouseover 、mouseout 、mouseleave 都与两个元素有关,本属性指向相关元素对象。 |
button | Integer | 触发鼠标按键事件的按键 | 0:鼠标左键;1:鼠标滚轮按钮;2:鼠标右键;3:鼠标"后退"键;4:鼠标"前进"键。 注意,click事件触发的只会是 0 。 |
buttons | Integer | 获取当前按下的多个鼠标按键 | 0:无任何按键;1:鼠标左键;2:鼠标滚轮按钮;4:鼠标右键;8:鼠标"后退"键;16:鼠标"前进"键。 注意,多个按键之间用"加法"表示,如,同时按下左右键则为 6 。 |
触摸事件一样继承自 UI Event 。一般在移动端设备或能够触摸设备上使用该事件。上面提到的鼠标事件,如,click
、mousedown
、mouseup
,通常状况下都能使用。触摸事件都是会冒泡的。
这几个触摸事件对象除了继承 UI Event 事件的属性外,还包含以下属性,都是 TouchList ,由 Touch 对象组成的类数组。每一个 touch 对象表示一个触摸点,touch 对象保存着跟触摸点相关的信息(如,id、位置信息、按压力度等)。
当用户按下键盘的按键就会触发键盘事件。键盘的事件有 3 个:
keydown
、keypress
、keyup
都是同类型的事件对象。都含有相同的属性,通常获取用户按下的按键再进行处理,详细请查看MDN文档。
还有复合事件(composition Event)是与键盘输入有关的,其实就是咱们常说的输入法。有三个复合事件:
这类事件对象中的data
属性是值得关注的。compositionstart
只表示启动了输入法,data的值永远为空。compositionupdate
表示正在向输入法输入字符,每次更新都会触发,以下图,当正在输入且未选择字符时,data的值与文本框显示的相同,即shu'ru'fa
;当选择字符后,data值会更新为选择的字符,即输入法
。compositionend
在关闭输入法时触发,因此data属性的值就是留在输入框内的值。
拖放事件是DragEvent
类型。用户经过将指针设备(例如鼠标)放置在触摸表面上而且而后将指针拖动到新位置(诸如另外一个DOM元素)来发起拖动。"拖放"实际是有两部分:拖(drag)和放(drop)。文本和图片是默承认以拖放的,而其余的 DOM 元素能够经过设置特性draggable="true"
达到能够拖放。
有以下拖放事件:
drop
事件才会触发。能够参考 MDN 文档的一个拖放例子。简单总结几点:
draggable="true"
才能拖放。removeChild
、appendChild
等。event.target
的样式设置,能够加强拖放时给用户的感觉。dragover
事件是drop
事件的前提,因此,不添加dragover
事件处理函数则没法触发drop
事件。drop
事件的默认行为是打开连接,经过event.preventDefault()
能够禁用其行为。设备事件一般包含两种:设备方向改变、设备被移动。一般用于手机和平板。都是window
对象上的事件。
事件对象的属性中关于方向的 x
、y
、z
轴以下图。事件对象的属性中关于面的alpha
对应的xy组成的面;bata
对应的是yz组成的面;gamma
对应的是zx组成的面。
具体事件以下:
Event
对象。注意,设备设定了"锁定旋转"将不会触发该事件。但事件对象自己并无太多可用信息,须要配合window.orientation
对象使用,用于获取设备的方向,window.orientation
可能有三个值:0 表示"垂直模式",即设备底部指向地面;90 表示左转的"横屏模式",即设备的左侧指向地面;-90 表示右转的"横屏模式",即设备的右侧指向地面。DeviceOrientationEvent
对象。是一个实验中的功能。DeviceMotionEvent
对象。是一个实验中的功能。null
。null
。null
。如下未写明的均为Event
类型的事件。
window
对象上。window
或document
对象上。window
对象上。不冒泡。使用该事件须要两个条件:鼠标焦点必须在该文档上;event.returnValue
必须赋值。window.addEventListener('beforeunload', (e) => {
// 原意是显示 returnValue 做为提示内容,但实际并没显示
// 但赋值是必须的,能够是任何值,不然不会触发事件
e.returnValue = ''
})复制代码
document.readyState
属性发生改变,readystatechange
事件会被触发。只能用在document
对象上。用途不大,通常咱们只关心加载完成的状态,使用DOMContentLoaded
事件便可。oldURL
和newURL
。但仍是建议使用location
对象肯定当前地址的参数列表。是HashChangeEvent
类型的事件。window
。事件对象中的persisted
属性值得关注,表示页面是否保存在内存中或是否从内存中加载(要注意两点:当页面从内存中加载,load事件不会触发;当设置了unload
事件,页面不会保存在内存中)。是PageTransitionEvent
类型的事件。form.submit()
例外,不会触发该事件。FocusEvent
类型的对象。FocusEvent
类型的对象。target
对象上的两个属性间接获取:selectionStart
、selectionEnd
。例子:e.target.value.substring(e.target.selectionStart,e.target.selectionEnd)
。开发者能够建立自定义事件,刻意触发特定事件,在测试 Web 应用时极其有用。
建立Event
对象须要使用new
关键字:event = new Event(typeArg, eventInit?);
,其中,typeArg
表示自定义事件的名称;eventInit
是可选参数,是一个对象,包含三个字段"bubbles"
、"cancelable"
、"composed"
中的任意多个。
// 建立一个 名为look,支持冒泡,不能被取消的 事件
let ev = new Event("look", {"bubbles":true, "cancelable":false});复制代码
每一个Element
对象都有一个dispatch(event)
方法,用于触发开发者建立的模拟事件,前提是已经给该元素添加事件监听函数,event
表示模拟事件对象。下面给出一个完成的例子:
<button id="btn1">按钮1</button>复制代码
// 建立模拟事件对象
let myEvent = new Event("eventName", {"bubbles":true, "cancelable":false});
// 获取元素对象,并添加事件监听
let btn = document.getElementById('btn1');
btn.addEventListener('eventName', e => console.log(e));
// 触发"eventName"事件
btn.dispatchEvent(myEvent);
复制代码
上面说起到的事件类型都可以做为构造函数。如,要建立DeviceMotionEvent
类型的事件对象,则let ev = new DeviceMotionEvent('evnetName', {});
便可,其余类型同理。
关于这部分,要说的只有两点:列表中使用的事件绑定,建议使用事件委托,如<li>均不添加事件处理函数,只在外层的<ul>添加,经过target判断是哪一个<li>再处理;删除元素前,先把绑定的事件函数移除。
过多事件致使性能降低的缘由:每一个函数都是对象,都会占用内存,对象越多性能越差;必须事先指定全部的事件处理函数而致使DOM访问次数过多,会延迟整个页面的交互就绪事件。