搜索
首页web前端js教程js事件监听机制(事件捕获)总结_javascript技巧

在前端开发过程中我们经常会遇到给页面元素添加事件的问题,添加事件的js方法也很多,有直接加到页面结构上的,有使用一些js事件监听的方法,由于各个浏览器对事件冒泡事件监听的机制不同,le浏览器只有事件冒泡,没有事件监听的机制,对于事件监听的兼容性问题是最大的难题:

1.直接把事件的方法写在页面结构上

function eventfun(){ 
//console.log(this); 
} 
<input type="button" onclick="eventfun()" value="button" />//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是[object Window],this指向的是window.

要解决this作用域的问题,可以使用为全局函数添加event变量的方法,在页面结构上将this对象作为参数传递到函数内部使用

<input type="button" onclick="eventfun2(this)" value="button2" /> 
function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 
eve.name="alex"; 
window.name="robin"; 
console.log(this);//[object Window] 
console.log(eve);// [object HTMLInputElement] 
console.log(this.name);// robin 
console.log(eve.name);// alexvar 
self=eve; 
console.log(this.name);//robin 
console.log(self.name);//alex 
alert(window.name); 
alert(self.name); 
}

2. 使用给事件属性赋值的方法,是一种为事件绑定的方法,但是这种方法的局限性就是只能为事件绑定一个方法,如果绑定多个就会以后一个方法为准

HTMLElementobject.onclick = fucntion(){//使用这种为事件属性赋值的方法,this的指针会指向window对象,而不是被事件对象,所以这种方法是引用

//js code 
fun1(); 
fun2(); 
fun3(); 
console.log(this);//window.object 
} 
function dosomething(){ 
//js code 
} 
HTMLElementobject.onclick = dosomething;//使用这种为事件对象属性赋值的形式,this指针指向事件执行对象 
console.log(this);//htmlElementObject

3.事件传播——冒泡与捕获
DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响。这两种事件流分别是捕获和冒泡。和许多Web技 术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们。Netscape选择实现了捕获事件流,微软则实现了冒泡事件流。幸运的 是,W3C决定组合使用这两种方法,并且大多数新浏览器都遵循这两种事件流方式。
默认情况下,事件使用冒泡事件流,不使用捕获事件流。然而,在Firefox和Safari里,你可以显式的指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true。
冒泡事件流
当事件在某一DOM元素被触发时,例如用户在客户名字节点上点击鼠标,事件将跟随着该节点继承自的各个父节点冒泡穿过整个的DOM节点层次,直到它 遇到依附有该事件类型处理器的节点,此时,该事件是onclick事件。在冒泡过程中的任何时候都可以终止事件的冒泡,在遵从W3C标准的浏览器里可以通 过调用事件对象上的stopPropagation()方法,在Internet Explorer里可以通过设置事件对象的cancelBubble属性为true。如果不停止事件的传播,事件将一直通过DOM冒泡直至到达文档根。
捕获事件流
事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有祖先元素依次往下传递。在这个过程中,事件会被从文档 根到事件目标元素之间各个继承派生的元素所捕获,如果事件监听器在被注册时设置了useCapture属性为true,那么它们可以被分派给这期间的任何 元素以对事件做出处理;否则,事件会被接着传递给派生元素路径上的下一元素,直至目标元素。事件到达目标元素后,它会接着通过DOM节点再进行冒泡。
现代事件绑定方法
针对如上节课所讨论的,使用传统事件绑定有许多缺陷,比如不能在一个对象的相同事件上注册多个事件处理函数。而浏览器和W3C也并非没有考虑到这一点,因此在现代浏览器中,它们有自己的方法绑定事件。
W3C DOM
obj.addEventListener(evtype,fn,useCapture)——W3C提供的添加事件处理函数的方法。obj是要添 加事件的对象,evtype是事件类型,不带on前缀,fn是事件处理函数,如果useCapture是true,则事件处理函数在捕获阶段被执行,否则 在冒泡阶段执行
obj.removeEventListener(evtype,fn,useCapture)——W3C提供的删除事件处理函数的方法
微软IE方法
obj.attachEvent(evtype,fn)——IE提供的添加事件处理函数的方法。obj是要添加事件的对象,evtype是事件类型,带on前缀,fn是事件处理函数,IE不支持事件捕获
obj.detachEvent(evtype,fn,)——IE提供的删除事件处理函数的方法,evtype包含on前缀

整合两者的方法

function addEvent(obj,evtype,fn,useCapture) { 
if (obj.addEventListener) { 
obj.addEventListener(evtype,fn,useCapture); 
} else { 
obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获 
} else { 
obj["on"+evtype]=fn;//事实上这种情况不会存在 
} 
} 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) { 
obj.removeEventListener(evtype,fn,useCapture); 
} else { 
obj.detachEvent("on"+evtype,fn); 
} else { 
obj["on"+evtype]=null; 
} 
}

IE的attach方法有个问题,就是使用attachEvent时在事件处理函数内部,this指向了window,而不是obj!当然,这个是有解决方案的!

但IE的attachEvent方法有另外一个问题,同一个函数可以被注册到同一个对象同一个事件上多次,解决方法:抛弃IE的 attachEvent方法吧!IE下的attachEvent方法不支持捕获,和传统事件注册没多大区别(除了能绑定多个事件处理函数),并且IE的 attachEvent方法存在内存泄漏问题!
addEvent,delEvent现代版

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>js事件监听</title> 
<style> 
table td{font:12px; border-bottom:1px solid #efefef;} 
</style> 
</head> 

<body> 
<div id="outEle" style="padding:10px; border:1px solid #b2b2b2; background:#efefef;"> 
<input type="button" onclick="eventfun()" id="button" value="button" /><br /> 
<input type="button" onclick="eventfun2(this);" id="button2" value="button2" /><br /> 
<input type="button" id="button3" value="button3" /><br /> 
<input type="button" id="button4" value="button4" /><br /> 
<table id="htmlEleTable" width="100%" border="0" style="border:1px solid #b2b2b2; background:#fff;"> 
<tr id="1111"><td>111111111111111111111111111111</td></tr> 
<tr id="22222"><td>222222222222222222222222222222</td></tr> 
<tr id="33333"><td>333333333333333333333333333333</td></tr> 
<tr id="4444"><td>444444444444444444444444444444</td></tr> 
<tr id="55555"><td>555555555555555555555555555555</td></tr> 
</table> 
</div> 
<script language="javascript" type="text/javascript"> 
function eventfun(){//1.直接把js方法写在页面结构上 
console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window 
alert(this); 
} 
function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 
eve.name="alex";// 
window.name="robin"; 
console.log(this);//[object Window] 
console.log(eve);// [object HTMLInputElement] 
console.log(this.name);// robin 
console.log(eve.name);// alex 
var self=eve; 
console.log(this.name);//robin 
console.log(self.name);//alex 
alert(window.name); 
alert(self.name); 
} 
function eventfun3(){//1.直接把js方法写在页面结构上 
console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window 
console.log(this.id); 
alert(this); 
alert(this.id); 
//var outEleObj = EventUtil.$("outEle"); 
//removeEvent(outEleObj,"click",eventfun3); 
} 
/* 
var EventUtil = {}; 
EventUtil.$ = function(id){ 
return document.getElementById(id); 
} 
EventUtil.openmes = eventfun3; 
EventUtil.addEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 
if(eventTarget.attachEvent){ 
eventTarget.attachEvent("on"+eventtype,eventHandle); 
}else if(eventTarget.addEventListener){ 
eventTarget.addEventListener(eventtype,eventHandle,false) 
}else{ 
eventTarget["on" + eventtype] = null; 
} 

}; 
EventUtil.deleEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 
if(eventTarget.detachEvent){ 
alert("on"+eventtype); 
alert("on"+eventHandle); 
eventTarget.detachEvent("on"+eventtype,eventHandle); 
}else if(eventTarget.removeEventListener){ 
eventTarget.removeEventListener(eventtype,eventHandle,false) 
}else{ 
eventTarget["on" + eventtype] = null; 
} 

};*/ 
var EventUtil={ 
$:function(id){ 
return document.getElementById(id); 
}, 
but4fun:function(){ 
console.log(this); 
this.addEventHandle(); 
}, 
eventfun3:function (){ 
console.log(this); 
alert(this); 
delEvent(obj,evtype,fn,useCapture); 
} 
} 
/***使用addEventListener,attachEvent进行dom事件的监听 
function addEvent(obj,evtype,fn,useCapture){ 
if (obj.addEventListener) { 
obj.addEventListener(evtype,fn,useCapture); 
}else if(obj.attachEvent){ 
obj.attachEvent("on"+evtype,function () { 
fn.call(obj); 
}); 
}else { 
obj["on"+evtype]=fn;//事实上这种情况不会存在 
} 
} 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) { 
obj.removeEventListener(evtype,fn,useCapture); 
} else if(obj.detachEvent){ 
obj.detachEvent("on"+evtype,fn); 
} else { 
obj["on"+evtype]=null; 
} 
} 



function addEvent(obj,evtype,fn,useCapture) { 
if (obj.addEventListener) {//优先考虑W3C事件注册方案 
obj.addEventListener(evtype,fn,!!useCapture); 
} else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定 
if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;} 
//为每个事件处理函数分配一个唯一的ID 

if (!obj.__EventHandles) {obj.__EventHandles={};} 
//__EventHandles属性用来保存所有事件处理函数的引用 

//按事件类型分类 
if (!obj.__EventHandles[evtype]) {//第一次注册某事件时 
obj.__EventHandles[evtype]={}; 
if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数 
(obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位 
//并且给原来的事件处理函数增加一个ID 
} 
obj["on"+evtype]=addEvent.execEventHandles; 
//当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数 
} 
} 
} 

addEvent.__EventHandlesCounter=1;//计数器,0位预留它用 
addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行 
if (!this.__EventHandles) {return true;} 
evt = evt || window.event; 
var fns = this.__EventHandles[evt.type]; 
for (var i in fns) { 
fns[i].call(this); 
} 
}; 
/* 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数 
obj.removeEventListener(evtype,fn,!!useCapture); 
} else { 
if (obj.__EventHandles) { 
var fns = obj.__EventHandles[evtype]; 
if (fns) {delete fns[fn.__EventID];} 
} 
} 
} 

function fixEvent(evt) {//fixEvent函数不是单独执行的,它必须有一个事件对象参数,而且只有事件发生时它才被执行!最好的方法是把它整合到addEvent函数的execEventHandles里面 
if (!evt.target) { 
evt.target = evt.srcElement; 
evt.preventDefault = fixEvent.preventDefault; 
evt.stopPropagation = fixEvent.stopPropagation; 
if (evt.type == "mouseover") { 
evt.relatedTarget = evt.fromElement; 
} else if (evt.type =="mouseout") { 
evt.relatedTarget = evt.toElement; 
} 
evt.charCode = (evt.type=="keypress")&#63;evt.keyCode:0; 
evt.eventPhase = 2;//IE仅工作在冒泡阶段 
evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间 
} 
return evt; 
} 
fixEvent.preventDefault =function () { 
this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent 
}; 
fixEvent.stopPropagation =function () { 
this.cancelBubble = true; 
};*/ 
//console.log(EventUtil.$("button3"));//返回EventUtil函数的对象属性 
//EventUtil.$("button3").onclick= eventfun;//2.使用为对象事件属性赋值的方法来实现事件的监听 
//EventUtil.$("button3").onclick= eventfun2;//为事件属性添加多个方法时,为后者 
//EventUtil.$("button3").onclick= eventfun;//事件捕获是从事件对象逐层外父级检察一直到window对象 
var EventUtil =function(){ 
function getByid(id){ 
return document.getElementById(id); 
}; 
// written by Dean Edwards, 2005 
// with input from Tino Zijdel, Matthias Miller, Diego Perini 

// http://dean.edwards.name/weblog/2005/10/add-event/ 

function addEvent(element, type, handler) { 
if (element.addEventListener) { 
element.addEventListener(type, handler, false); 
} else { 
// assign each event handler a unique ID 
if (!handler.$$guid) handler.$$guid = addEvent.guid++; 
// create a hash table of event types for the element 
if (!element.events) element.events = {}; 
// create a hash table of event handlers for each element/event pair 
var handlers = element.events[type]; 
if (!handlers) { 
handlers = element.events[type] = {}; 
// store the existing event handler (if there is one) 
if (element["on" + type]) { 
handlers[0] = element["on" + type]; 
} 
} 
// store the event handler in the hash table 
handlers[handler.$$guid] = handler; 
// assign a global event handler to do all the work 
element["on" + type] = handleEvent; 
} 
}; 
// a counter used to create unique IDs 
addEvent.guid = 1; 

function removeEvent(element, type, handler) { 
if (element.removeEventListener) { 
element.removeEventListener(type, handler, false); 
} else { 
// delete the event handler from the hash table 
if (element.events && element.events[type]) { 
delete element.events[type][handler.$$guid]; 
} 
} 
}; 

function handleEvent(event) { 
var returnValue = true; 
// grab the event object (IE uses a global event object) 
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); 
// get a reference to the hash table of event handlers 
var handlers = this.events[event.type]; 
// execute each event handler 
for (var i in handlers) { 
this.$$handleEvent = handlers[i]; 
if (this.$$handleEvent(event) === false) { 
returnValue = false; 
} 
} 
return returnValue; 
}; 

function fixEvent(event) { 
// add W3C standard event methods 
event.preventDefault = fixEvent.preventDefault; 
event.stopPropagation = fixEvent.stopPropagation; 
return event; 
}; 
fixEvent.preventDefault = function() { 
this.returnValue = false; 
}; 
fixEvent.stopPropagation = function() { 
this.cancelBubble = true; 
}; 
function tableAddEvent(){ 

}; 

return{ 
add:addEvent, 
remove:removeEvent, 
$:getByid 
} 
}(); 

var outEleObj = EventUtil.$("outEle"); 
//addEvent.apply(EventUtil,[outEleObj,"click",eventfun3]); 
//EventUtil.add(outEleObj,"click",eventfun3); 
var inputObj = EventUtil.$("button4"); 
var tableEle = EventUtil.$("htmlEleTable"); 
var tabTrEle = tableEle.getElementsByTagName("tr"); 
EventUtil.add(tableEle,"click",eventfun3); 
for (i=0; i<tabTrEle.length; i++){ 
EventUtil.add(tabTrEle[i],"click",eventfun3); 
} 
EventUtil.remove(tableEle,"click",eventfun3);//事件冒删除方法 
EventUtil.add(tableEle,"click",eventfun3);//事件冒泡添加方法 
//EventUtil.add(inputObj,"click",eventfun3); 
//EventUtil.remove(outEleObj,"click",eventfun3); 
//console.log(addEvent); 
//addEvent(inputObj,"click",eventfun3,true); 
//delEvent(outEleObj,"click",eventfun3,false); 
</script> 
</body> 
</html>

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
js中点击事件为什么不能重复执行js中点击事件为什么不能重复执行May 07, 2024 pm 06:36 PM

JavaScript 中的点击事件不能重复执行,原因在于事件冒泡机制。为了解决此问题,可以采取以下措施:使用事件捕获:指定事件侦听器在事件冒泡之前触发。移交事件:使用 event.stopPropagation() 阻止事件冒泡。使用计时器:在一段时间后再次触发事件侦听器。

有效阻止事件冒泡的方法有效阻止事件冒泡的方法Feb 19, 2024 pm 08:25 PM

如何有效地阻止事件冒泡,需要具体代码示例事件冒泡是指当一个元素上的事件触发时,父级元素也会收到相同的事件触发,这种事件传递机制有时会给网页开发带来麻烦,因此我们需要学习如何有效地阻止事件冒泡。在JavaScript中,我们可以通过使用事件对象的stopPropagation()方法来阻止事件冒泡。该方法可以在事件处理函数中调用,以停止事件继续传播到父级元素。

利用JavaScript和腾讯地图实现地图事件监听功能利用JavaScript和腾讯地图实现地图事件监听功能Nov 21, 2023 pm 04:10 PM

很抱歉,但我无法为您提供完整的代码示例。不过我可以为您提供一个基本的思路和示例代码段,以供参考。下面是一个简单的JavaScript和腾讯地图结合的示例,用于实现地图事件监听的功能://引入腾讯地图的APIconstscript=document.createElement('script');script.src='https://map.

事件捕获有什么作用事件捕获有什么作用Nov 01, 2023 pm 01:16 PM

事件捕获的作用包括方便获取目标元素和上下文信息、有效防止事件冒泡、自定义事件处理逻辑和提高页面响应速度等。详细介绍:1、方便获取目标元素和上下文信息,在事件捕获阶段,当一个事件发生时,浏览器会从最外层元素开始逐层向下查找与该事件相关联的元素,直到找到目标元素为止;2、有效防止事件冒泡,在事件模型中,一个事件发生时,会从最外层元素开始逐层向下传递,这个过程被称为事件冒泡等等。

前端开发中的事件冒泡和事件捕获的实际应用案例前端开发中的事件冒泡和事件捕获的实际应用案例Jan 13, 2024 pm 01:06 PM

事件冒泡与事件捕获在前端开发中的应用案例事件冒泡和事件捕获是前端开发中经常用到的两种事件传递机制。通过了解和应用这两种机制,我们能够更加灵活地处理页面中的交互行为,提高用户体验。本文将介绍事件冒泡和事件捕获的概念,并结合具体的代码示例,展示它们在前端开发中的应用案例。一、事件冒泡和事件捕获的概念事件冒泡(EventBubbling)事件冒泡是指在触发一个元

什么是事件冒泡事件捕获什么是事件冒泡事件捕获Nov 21, 2023 pm 02:10 PM

事件冒泡和事件捕获是指在HTML DOM中处理事件时,事件传播的两种不同方式。详细介绍:1、事件冒泡是指当一个元素触发了某个事件,该事件将从最内层的元素开始传播到最外层的元素。也就是说,事件首先在触发元素上触发,然后逐级向上冒泡,直到达到根元素;2、事件捕获则是相反的过程,事件从根元素开始,逐级向下捕获,直到达到触发事件的元素。

vue中常用的修饰符vue中常用的修饰符May 08, 2024 pm 04:27 PM

Vue.js 的修饰符用于修改指令行为,常用的修饰符包括:延迟执行(.lazy)、缓存计算结果(.memo)、强制转换为数字(.number)、修剪空格(.trim)、阻止默认行为(.prevent)、阻止事件冒泡(.stop)、仅执行一次(.once)、仅在当前元素触发(.self)、在事件捕获阶段触发(.capture)、在元素进入 DOM 时触发(.enter)、在元素离开 DOM 时触发(.leave)。

事件冒泡引发的常见问题与解决方案事件冒泡引发的常见问题与解决方案Feb 20, 2024 pm 06:48 PM

事件冒泡(eventbubbling)是指在DOM中,当一个元素上的事件被触发时,它会向上冒泡到该元素的父级元素,再向上冒泡到更高级别的父级元素,直至冒泡到文档的根节点。虽然事件冒泡在许多情况下非常有用,但有时它也会引发一些常见的问题。本文将讨论一些常见的问题,并提供解决方案。第一个常见问题是多次触发事件。当一个元素上的事件冒泡到了多个父级元素时,可能会导

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
1 个月前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)