DOM中事件处理概览与原理的全面解析

网友投稿 203 2023-07-09


DOM中事件处理概览与原理的全面解析

事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信,DOM支持大量的事件;

本文通过这几点向大家详细解析事件处理的基本原理:事件类型、事件目标、事件处理程序、事件对象、事件传播

最后再向大家介绍Event对象;

一、事件类型(event type):是一个用来说明发生了什么类型事件的全小写的字符串,如‘mouseover'

传统事件类型:表单事件,Window事件,鼠标事件,键盘事件,DOM事件, HTML5事件,触摸屏和移动设备事件等

二、事件目标(event target):触发事件的对象

三、事件处理程序(或事件监听程序)(event listener):处理或响应事件的函数。当某对象触发某事件时,浏览器将自动调用在该对象上注册的函数;

注册事件处理程序(监听事件):

1.作为HTML属性注册(只会在冒泡阶段触发)如

onafterprint onfocus ononline onresize onbeforeprint onhashchange 

onpagehide onstorage onbeforeunload onload onpageshow onundo 

onblur onmessage onpopstate onunload onerror onoffline onredo

作为HTML属性的事件的值是js代码字符串,是处理函数的主体,不含{},注意:尽量不要在任何其他HTML标签上注册事件,它违反了HTML与javascript代码相分离的原则,倘若事件函数可能还没加载进来就点击了事件对象元素,这会导致错误;

2.作为DOM元素的属性来注册(只会在冒泡阶段触发),此时的事件处理程序属性的名字需加‘on'前缀,这种方式兼容所有浏览器,唯一的缺点是只能注册一个事件处理函数,如果定义两次onclick属性,后一次定义会NyQVD覆盖前一次;如:window.onload = function(){...};

3.除了IE8及之前版本外的所有浏览器中,DOM的事件操作(监听和触发),都定义在EventTarget接口。Element节点、document节点和window对象,都部署了这个接口。此外,XMLHttpRequest、AudioNode、AudioContext等浏览器内置对象,也部署了这个接口。该接口有三个方法,addEventListener和removeEventListener用于绑定和移除监听函数,dispatchEvent用于触发事件;

addEventListener(type,listener,boolean)方法来注册listener,第三个参数设置事件的传播方式,通常使用默认值false,表示监听函数只在冒泡阶段(pupple)被触发,当设为true时,表示监听函数在捕获阶段(capture)触发;可以为同一对象上的同一类型事件注册任意多个listener,所有listener会按照注册顺序触发(注册重复的listener将会被浏览器忽略);

如果希望向监听函数传递参数,可以用匿名函数包装一下监听函数,如elm.addEventListener('click',function(){listen('实参')},false);

当注册的listener是一个对函数的引用变量,就可以用removeEventLestener(type,listener,boolean)在事件目标上删除该listener,对同一监听事件的冒泡事件和捕获事件需要分别删除,两者互不干扰;

var div = document.getElementById('div');

var listener = function NyQVD(event) {

/* do something here */

};

div.addEventListener('click', listener, false);

div.removeEventListener('click', listener, false);

dispatchEvent(event)方法在当前节点上手动触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),就返回false,否则为true,参数是一个Event对象的实例,该参数不能为空,且必须是一个有效的事件对象,否则报错;

btn.addEventListener('click', listener, false);

     var e = new Event('click');

btn.dispatchEvent(e); //在btn上立即触发clicNyQVDk事件,将立即调用listener

下面例子根据dispatchEvent方法的返回值,判断事件是否被取消了

var canceled = !btn.dispatchEvent(event);

if (canceled) { console.log('事件取消'); } 

else { console.log('事件未取消'); }}

4.IE8及之前版本仅支持attachEvent (type,listener)和detachEvent(type,listener),它们的用法和addEventListener的区别:a.参数只有两个;b.参数type必须加'on'前缀;c.它允许对同一监听事件进行重复注册,且都会被调用;d.使用attachEvent方法有个缺点,是this的值会变成 window 对象而不是触发事件的元素;

调用顺序问题:1).通过设置对象属性或HTML属性注册的处理程序一直优先调用;

                         2).使用addEventListener 注册的处理程序按照它们的注册顺序调用;

                         3).旧版IE中使用attachEvent注册的处理程序可能按照任何顺序调用。

返回值问题:

1).事件处理程序的返回值只对通过属性注册的处理程序才有意义,通过设置对象属性或HTML属性注册 事件处理程序的返回值为false,就是告诉浏览器不要执行这个事件相关的默认操作。当浏览器要跳转到新页面时触发Window对象的onbeforeunload事件,若它的的返回值为字符串,则它将出现在询问确认对话框中;

2).addEventListener()或attachEvent()注册事件处理程序若要取消浏览器的默认操作必须调用preventDefault()方法或设置事件对象的returnValue属性。

this指向问题:

1).addEventListener方法指定的监听函数,内部的this对象总是指向触发事件的那个节点;

2).IE8及以前的attachEvent方法注册的事件处理函数的this指向全局对象;

以下写法的this对象都指向Element节点。 

                    element.onclick = print;

                    element.addEventListener('click', print, false)

                    element.onclick = function () {console.log(this.id);}

                   

 以下写法的this对象,都指向全局对象。 

                    element.onclick = function (){ doSomething() }; 

                    element.setAttribute('onclick', 'doSomething()'); 

                     

                    element.attachEvent('onclick',doSomething) //IE8

内存问题:对如下代码,每个循环中都会创建一个新的匿名函数,占用的内存越来越多;由于没有保持到匿名函数的引用,它不可能被调用 removeEventListener;所以应当把第二参数listener保持为对处理事件函数的引用;

for(i=0 ; i

els[i].addEventListener("click", function(e){/*do something*/}, false});

}

通用的兼容旧版IE的工具函数:

确保事件处理程序的this指向事件的目标对象的工具函数addEvent

function addEvent(target,type,func){

if(target.addEventListener){

target.addEventListener(type,func,false);

}else{

target.attachEvent('on'+type,function(e){ //这里attachEvent注册的处理函数未绑定引用,所以无法用detachEvent删除

return func.call(target,e);

});

}

}

通用的事件处理程序(因为IE8及以前版本,作为事件目标的on-属性的处理程序需要window.event来获得事件对象,且触发事件的目标节点对象通过event.srcElement属性获得)

function func(event){

var event = event||window.event;

var target = event.target || event.srcElement;

//......处理程序代码

}

四、事件传播(event propagation):是浏览器决定哪个对象触发其事件处理程序的过程。

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段==>处于目标阶段==>事件冒泡阶段。首先发生的是事件捕获阶段(从外层向内层传播),为事件传播经过的所有节点截获事件提供了机会。然后是实际的目标接收事件(按注册顺序执行)。最后一个阶段是冒泡阶段(从内层向外层冒泡)。

当容器元素及嵌套元素,即在捕获阶段又在冒泡阶段调用事件处理程序时:事件按DOM事件流的顺序执行事件处理程序,且当事件处于目标阶段时,事件调用顺序决定于绑定事件的书写顺序

如果希望事件到某个节点为止,不再传播,有两种方式:

1.使用事件对象的event.stopPropagation()方法来阻止当前监听函数的传播;

2.使用事件对象的event.stopImmediatePropagation()方法来阻止当前事件在其事件对象上的所有监听函数的传播;

事件的代理(delegation):由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件;

五、事件对象(Event):事件发生以后,会生成一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。Event对象本身就是一个构造函数,可以用来生成新的实例。

var ev = new Event("look", {"bubbles":true, "cancelable":false});

document.dispatchEvent(ev);

Event构造函数接受两个参数。第一个参数是字符串,表示事件的名称;第二个参数是一个对象,表示事件对象的配置。该参数可以有以下两个属性。

bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。

cancelable:布尔值,可选,默认为false,表示事件是否可以被取消。

Event对象的属性:

1.与事件的阶段有关: 

bubbles: 只读属性,返回一个布尔值,表示当前事件是否会冒泡,可根据事件是否会冒泡来调用不同的函数。 

eventPhase:返回一个整数值(0,1,2,3之一),表示事件目前所处的状态

<0,事件目前没有发生。

<1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。该过程是从Window对象到Document节点,再到HTMLHtmlElement节点,直到目标节点的父节点为止。

<2,事件到达目标节点,即target属性指向的那个节点。

<3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。该过程是从父节点一直到Window对象。只有bubbles属性为true时,这个阶段才可能发生

2.与事件的默认行为有关: 

cancelable:返回一个布尔值,表示事件是否可以取消。如果要取消某个事件,需要在这个事件上面调用preventDefault方法 

defaultPrevented:返回一个布尔值,表示该事件是否调用过preventDefault方法。

3.与事件的目标节点有关: 

currentTarget:返回事件执行的监听函数所绑定的那个节点。 

target:返回触发事件的那个节点。在IE6—IE8之中,该属性的名字不是target,而是srcElement

4.与事件对象的其他信息相关: 

type:返回一个字符串,表示事件类型 

detail:返回一个数值,表示事件的某种信息。具体含义与事件类型有关,对于鼠标事件,表示鼠标按键在某个位置按下的次数,比如对于dblclick事件,detail属性的值总是2 

timeStamp:返回一个毫秒时间戳,表示事件发生的时间。从PerformanceTiming.navigationStart开始计算,即表示距离用户导航至该网页的时间。如果想将这个值转为Unix纪元时间戳,就要计算event.timeStamp + performance.timing.navigationStart

isTrusted:返回一个布尔值,表示该事件是否可以信任。用处不大,不同浏览器的支持不一样。

Event对象的方法: 

preventDefault():取消浏览器对当前事件的默认行为,该方法生效的前提是,事件的cancelable属性为true,如果为false,则调用该方法没有任何效果。 

stopPropagation():终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。注意:该方法不能阻止同一个 Document 节点上的其他事件句柄被调用,但是它可以阻止把事件分派到其他节点 

stopImmediatePropagation():阻止同一个事件的其他监听函数被调用,只要其中有一个监听函数调用了该方法,其他的监听函数就不会再执行了。

参考链接: 

http://javascript.ruanyifeng.com/dom/event.html#toc31 

https://developer.mozilla.org/zh-CN/docs/Web/API 

JavaScript权威指南第六版

els[i].addEventListener("click", function(e){/*do something*/}, false});

}

通用的兼容旧版IE的工具函数:

确保事件处理程序的this指向事件的目标对象的工具函数addEvent

function addEvent(target,type,func){

if(target.addEventListener){

target.addEventListener(type,func,false);

}else{

target.attachEvent('on'+type,function(e){ //这里attachEvent注册的处理函数未绑定引用,所以无法用detachEvent删除

return func.call(target,e);

});

}

}

通用的事件处理程序(因为IE8及以前版本,作为事件目标的on-属性的处理程序需要window.event来获得事件对象,且触发事件的目标节点对象通过event.srcElement属性获得)

function func(event){

var event = event||window.event;

var target = event.target || event.srcElement;

//......处理程序代码

}

四、事件传播(event propagation):是浏览器决定哪个对象触发其事件处理程序的过程。

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段==>处于目标阶段==>事件冒泡阶段。首先发生的是事件捕获阶段(从外层向内层传播),为事件传播经过的所有节点截获事件提供了机会。然后是实际的目标接收事件(按注册顺序执行)。最后一个阶段是冒泡阶段(从内层向外层冒泡)。

当容器元素及嵌套元素,即在捕获阶段又在冒泡阶段调用事件处理程序时:事件按DOM事件流的顺序执行事件处理程序,且当事件处于目标阶段时,事件调用顺序决定于绑定事件的书写顺序

如果希望事件到某个节点为止,不再传播,有两种方式:

1.使用事件对象的event.stopPropagation()方法来阻止当前监听函数的传播;

2.使用事件对象的event.stopImmediatePropagation()方法来阻止当前事件在其事件对象上的所有监听函数的传播;

事件的代理(delegation):由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件;

五、事件对象(Event):事件发生以后,会生成一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。Event对象本身就是一个构造函数,可以用来生成新的实例。

var ev = new Event("look", {"bubbles":true, "cancelable":false});

document.dispatchEvent(ev);

Event构造函数接受两个参数。第一个参数是字符串,表示事件的名称;第二个参数是一个对象,表示事件对象的配置。该参数可以有以下两个属性。

bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。

cancelable:布尔值,可选,默认为false,表示事件是否可以被取消。

Event对象的属性:

1.与事件的阶段有关: 

bubbles: 只读属性,返回一个布尔值,表示当前事件是否会冒泡,可根据事件是否会冒泡来调用不同的函数。 

eventPhase:返回一个整数值(0,1,2,3之一),表示事件目前所处的状态

<0,事件目前没有发生。

<1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。该过程是从Window对象到Document节点,再到HTMLHtmlElement节点,直到目标节点的父节点为止。

<2,事件到达目标节点,即target属性指向的那个节点。

<3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。该过程是从父节点一直到Window对象。只有bubbles属性为true时,这个阶段才可能发生

2.与事件的默认行为有关: 

cancelable:返回一个布尔值,表示事件是否可以取消。如果要取消某个事件,需要在这个事件上面调用preventDefault方法 

defaultPrevented:返回一个布尔值,表示该事件是否调用过preventDefault方法。

3.与事件的目标节点有关: 

currentTarget:返回事件执行的监听函数所绑定的那个节点。 

target:返回触发事件的那个节点。在IE6—IE8之中,该属性的名字不是target,而是srcElement

4.与事件对象的其他信息相关: 

type:返回一个字符串,表示事件类型 

detail:返回一个数值,表示事件的某种信息。具体含义与事件类型有关,对于鼠标事件,表示鼠标按键在某个位置按下的次数,比如对于dblclick事件,detail属性的值总是2 

timeStamp:返回一个毫秒时间戳,表示事件发生的时间。从PerformanceTiming.navigationStart开始计算,即表示距离用户导航至该网页的时间。如果想将这个值转为Unix纪元时间戳,就要计算event.timeStamp + performance.timing.navigationStart

isTrusted:返回一个布尔值,表示该事件是否可以信任。用处不大,不同浏览器的支持不一样。

Event对象的方法: 

preventDefault():取消浏览器对当前事件的默认行为,该方法生效的前提是,事件的cancelable属性为true,如果为false,则调用该方法没有任何效果。 

stopPropagation():终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。注意:该方法不能阻止同一个 Document 节点上的其他事件句柄被调用,但是它可以阻止把事件分派到其他节点 

stopImmediatePropagation():阻止同一个事件的其他监听函数被调用,只要其中有一个监听函数调用了该方法,其他的监听函数就不会再执行了。

参考链接: 

http://javascript.ruanyifeng.com/dom/event.html#toc31 

https://developer.mozilla.org/zh-CN/docs/Web/API 

JavaScript权威指南第六版


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:介绍Java的大数类(BigDecimal)和八种舍入模式
下一篇:java selenium 常见web UI 元素操作及API使用
相关文章

 发表评论

暂时没有评论,来抢沙发吧~