事件的本质是程序各个组成部分之间的一种通讯方式,也是异步编程的一种实现。DOM支持大量的事件,本章开始介绍DOM的事件编程。javascript
浏览器的事件模型,就是经过监听函数(listener)对事件作出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。html
DOM事件流(event flow)有两种:事件冒泡、事件捕获。不管是事件捕获仍是事件冒泡,它们都有一个共同的行为事件传播。它就像一跟引线,只有经过引线才能将绑在引线上的鞭炮(事件监听器)引爆。java
DOM标准事件流的触发的前后顺序为:先捕获再冒泡。即当触发DOM事件时,会先进行事件捕获,捕获到事件源以后经过事件传播进行事件冒泡。不一样的浏览器对此有着不一样的实现:IE10及如下不支持捕获型事件,因此就少了一个事件捕获阶段,IE十一、Chrome 、Firefox、Safari等浏览器则同时存在。编程
若是但愿事件到某个节点为止,再也不向上或向下传播,可使用事件对象的event.stopPropagation()
方法。它会阻止事件继续捕获或者冒泡。若是想要完全取消该事件,再也不触发该节点所拥有的某个事件的全部监听函数,可使用event.stopImmediatePropagation()
方法。浏览器
<body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> // 经过"addEventListener"方法,采用事件冒泡方式给dom元素注册click事件 var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.info("click-body"); },false); parent.addEventListener("click",function(e){ console.info("click-parent"); },false); child.addEventListener("click",function(e){ console.info("click-child"); },false); </script> </body>
事件捕获(event capturing):顺序是由外到内进行事件传播,直到叶子节点。如点击了子元素,若是父元素经过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。dom
// 在原始代码新增事件捕获事件代码 parent.addEventListener("click",function(e){ console.info("click-parent--事件捕获"); },true); // 点击子元素依次会输出:click-parent--事件捕获、click-child、click-parent、click-body
事件冒泡(dubbed bubbling):顺序是由内到外进行事件传播,直到根节点。异步
// 上述过程,点击子元素依次会输出:click-child、click-parent、click-body // 若是点击子元素不想触发父元素的事件怎么办 // 在原始代码新增中止事件传播--event.stopPropagation() child.addEventListener("click",function(e){ console.info("click-child"); e.stopPropagation(); },false); // 点击子元素只会输出:click-child
事件委托还有一个名字叫事件代理,通常用于动态生成的元素。事件委托是利用事件冒泡原理来实现的,只指定一个事件处理程序,就能够管理某一类型的全部事件。异步编程
有三个同事预计会在周一收到快递。为签收快递有两种办法:一是三我的在公司门口等快递;二是委托给前台代为签收。现实当中大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,而后按照收件人的要求签收,甚至代为付款。这种方案还有一个优点,那就是即便公司里来了新员工(无论多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。这里有2层意思的:函数
- 如今委托前台的同事是能够代为签收的,即程序中的现有的dom节点是有事件的
- 新员工也是能够被前台MM代为签收的,即程序中新添加的dom节点也是有事件的
通常来讲,DOM须要有事件处理程序,直接给它设事件处理程序就行了!若是是不少的DOM(好比有100个li)须要添加事件处理呢?每一个li都有相同的click点击事件,可能会用for循环的方法来遍历全部的li,而后给它们添加事件,那这么作会存在什么影响呢?性能
- 减小内存消耗:每一个函数都是一个对象,对象越多内存占用率就越大,天然性能就越差了。如100个li就要占用100个内存空间。若是用事件委托,那么就能够只对它的父级
<ul>
这一个对象进行操做,这样须要一个内存空间就够了。- 减小DOM操做:在JS中,添加到页面上的事件处理程序数量将直接关系到页面的总体运行性能,由于须要不断的与dom节点进行交互。访问dom的次数越多,引发浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间。若是要用事件委托,就会将全部的操做放到js程序里面,与dom的操做就只须要交互一次,这样就能大大的减小与dom的交互次数,提升性能。
因为事件会在冒泡阶段向上传播到父节点,所以能够把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。适合用事件委托的事件:click、keydown、keyup、keypress。不适合的主要分为两大类:一类是没有冒泡机制的,如focus、blur;另外一类是每次都要计算它的位置而很是很差把控的如mousemove。
DOM 的事件操做(监听和触发),都定义在EventTarget
接口。全部节点对象都部署了这个接口,其余一些须要事件通讯的浏览器内置对象(如XMLHttpRequest、
AudioNode、
AudioContext)也部署了这个接口。
EventTarget.addEventListener()
用于在当前节点或对象上,定义一个特定事件的监听函数,一旦这个事件发生,就会执行监听函数。该方法能够为当前对象的同一个事件添加多个不一样的监听函数:这些函数按照添加顺序触发;若是为同一个事件屡次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除。该方法接受三个参数:
type
:事件名称,大小写敏感。
listener
:监听函数。事件发生时会调用该监听函数。该参数除了监听函数,还但是一个具备handleEvent
方法的对象。监听函数内部的this
指向当前事件所在的那个对象。
useCapture
:布尔值,表示监听函数是否在捕获阶段(capture)触发,默认为false
(监听函数只在冒泡阶段被触发)。该参数可选外,还但是一个属性配置对象。该对象有如下属性:
once
:布尔值,表示监听函数是否只触发一次,而后就自动移除。capture
:布尔值,表示该事件是否在捕获阶段
触发监听函数。passive
:布尔值,表示监听函数不会调用事件的preventDefault
方法。若是监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。
EventTarget.removeEventListener
方法用来移除addEventListener
方法添加的事件监听函数。注意若是该方法要生效,其三个参数必须与addEventListener
方法彻底一致。
EventTarget.dispatchEvent
方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault()
,则返回值为false
,不然为true
。该方法的参数是一个Event
对象的实例。
事件发生之后,会产生一个事件对象,做为参数传给监听函数。浏览器原生提供一个Event
对象,全部的事件都是这个对象的实例,如鼠标事件、键盘事件、触摸事件、表单事件等,详情见这里。
Event
构造函数接受两个参数。第一个参数type
是字符串,表示事件的名称;第二个参数options
是一个对象,表示事件对象的配置。该对象主要有下面两个属性。
bubbles
:布尔值(可选),默认为false
,表示事件对象是否冒泡。cancelable
:布尔值(可选),默认为false
,表示事件是否能够被取消,即可否用Event.preventDefault()
取消这个事件。一旦事件被取消,就好像历来没有发生过,不会触发浏览器对该事件的默认行为。Event.type
属性返回一个字符串,表示事件类型。
Event.bubbles
属性返回一个布尔值,表示当前事件是否会冒泡。
Event.eventPhase
属性返回一个整数常量,表示事件目前所处的阶段。返回值有四种可能:
- 0:事件目前没有发生
- 1:事件处于捕获阶段
- 2:事件到达目标节点
- 3:事件处于冒泡阶段
Event.target
属性返回原始触发事件的那个节点,即事件最初发生的节点。
Event.currentTarget
属性返回事件当前所在的节点,即事件当前正在经过的节点。
Event.preventDefault
方法取消浏览器对当前事件的默认行为。好比点击连接后,浏览器默认会跳转到另外一个页面,使用这个方法之后,就不会跳转了。注意该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。Event.stopPropagation
方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,可是不包括在当前节点上该事件其余监听函数执行状况。Event.stopImmediatePropagation
方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,同时也包括在当前节点上该事件其余监听函数再也不执行。