js事件监听机制(事件捕获)总结

在前端开发过程中我们经常会遇到给页面元素添加事件的问题,添加事件的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")?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>

PS:这里再为大家提供一个关于JS事件的在线工具,归纳总结了JS常用的事件类型与函数功能:

javascript事件与功能说明大全:

http://tools.jb51.net/table/javascript_event

(0)

相关推荐

  • JS的事件绑定深入认识

    一.传统事件模型 传统事件模型中存在局限性. 内联模型以HTML标签属性的形式使用,与HTML混写,这种方式无疑造成了修改以及扩展的问题,已经很少使用了. 脚本模型是将事件处理函数写到js文件中,从页面获取元素进行对应事件函数的绑定以触发执行.但也存在不足之处: 1.一个事件绑定多个事件监听函数,后者将覆盖前者. 2.需要限制重复绑定的情况 3.标准化event对象 二.现代事件绑定 DOM2级事件定义了两个方法用于添加.删除事件:addEventListener().removeEventLi

  • js之事件冒泡和事件捕获详细介绍

    (1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div -> body -> html -> document Mozilla 1.0: div -> body -> html -> document -> window (2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开

  • js 事件的传播机制(实例讲解)

    事件的默认传播机制: 捕获阶段:从外向里依次查找元素 目标阶段:从当前事件源本身的操作 冒泡阶段:从内到外依次触发相关的行为(我们最常用的就是冒泡阶段) 具体见下图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #outer{ margin

  • js事件监听机制(事件捕获)总结

    在前端开发过程中我们经常会遇到给页面元素添加事件的问题,添加事件的js方法也很多,有直接加到页面结构上的,有使用一些js事件监听的方法,由于各个浏览器对事件冒泡事件监听的机制不同,le浏览器只有事件冒泡,没有事件监听的机制,对于事件监听的兼容性问题是最大的难题: 1.直接把事件的方法写在页面结构上 function eventfun(){ //console.log(this); } <input type="button" onclick="eventfun()&qu

  • 详谈Java中的事件监听机制

    鼠标事件监听机制的三个方面: 1.事件源对象: 事件源对象就是能够产生动作的对象.在Java语言中所有的容器组件和元素组件都是事件监听中的事件源对象.Java中根据事件的动作来区分不同的事件源对象,动作发生在哪个组件上,那么该组件就是事件源对象 2.事件监听方法: addMouseListener(MouseListener ml) ;该方法主要用来捕获鼠标的释放,按下,点击,进入和离开的动作:捕获到相应的动作后,交由事件处理类(实现MouseListener接口)进行处理. addAction

  • JS 事件绑定、事件监听、事件委托详细介绍

    在JavaScript的学习中,我们经常会遇到JavaScript的事件机制,例如,事件绑定.事件监听.事件委托(事件代理)等.这些名词是什么意思呢,有什么作用呢? 事件绑定 要想让 JavaScript 对用户的操作作出响应,首先要对 DOM 元素绑定事件处理函数.所谓事件处理函数,就是处理用户操作的函数,不同的操作对应不同的名称. 在JavaScript中,有三种常用的绑定事件的方法: 在DOM元素中直接绑定: 在JavaScript代码中绑定: 绑定事件监听函数. 在DOM中直接绑定事件

  • .NET事件监听机制的局限与扩展分析

    本文实例分析了.NET事件监听机制的局限与扩展.分享给大家供大家参考.具体分析如下: .NET中把"事件"看作一个基本的编程概念,并提供了非常优美的语法支持,对比如下C#和Java代码可以看出两种语言设计思想之间的差异. 复制代码 代码如下: // C# someButton.Click += OnSomeButtonClick; 复制代码 代码如下: // Java someButton.addActionListener(     new ActionListener(){    

  • Spring事件监听机制观察者模式详解

    目录 前言 观察者模式 观察者的角色定义 Java中的事件机制 Spring中的事件机制 Spring事件监听案例 小结 前言 Spring中提供了一套默认的事件监听机制,在容器初始化时便使用了这套机制.同时,Spring也提供了事件监听机制的接口扩展能力,开发者基于此可快速实现自定义的事件监听功能. Spring的事件监听机制是在JDK事件监听的基础上进行的扩展,也是在典型观察者模式上的进一步抽象和改进.所以,结合Spring的事件监听机制与观察者模式来学习,可以达到理论与实践的完美融合. 本

  • JavaGUI事件监听机制超详细讲解

    1.一个事件模型中有上对象:事件源,事件以及监听程序 2.事件监听机制: 事件源        事件发生的地方 事件            要发生的事情 事件处理     针对发生的事情做出的处理方案 事件监听     把事件源和事件关联起来 使用步骤: 新建一个组件(如 JButton) 将该组件添加到相应的面板(如 JFrame) 注册监听器以监听事件源产生的事件(如通过ActionListener来响应用户点击按钮) 定义处理事件的方法(如在ActionListener中的actionPe

  • javascript事件监听与事件委托实例详解

    本文实例讲述了javascript事件监听与事件委托.分享给大家供大家参考,具体如下: 事件监听与事件委托 在js中,常用到element.addEventListener()来进行事件的监听.但是当页面中存在大量需要绑定事件的元素时,这种方式可能会带来性能影响.此时,我们可以用事件委托的方式来进行事件的监听. 每个事件都经历三个阶段 捕获 到达目标 冒泡 事件委托需要用到事件的冒泡,冒泡就是事件发生时,上层会一层一层的接收这个事件. 如下页面结构: <body> <div id=&qu

  • Spring的事件监听机制示例详解

    前言 最近公司在重构广告系统,其中核心的打包功由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统.因此,为了将apk打包的核心流程和对接广告系统的业务解耦,利用了spring的事件监听特性来满足需求.以下说明spring的事件机制的相关内容. 首先spring事件分为事件发布者(EventPublisher).事件监听者(EventListener),还包括一个事件广播者(这个是spring实现相关,这一节不讨论).使用spring事件机制,需要自定义事件发布

  • Java事件监听机制讲解

    给组件加上监听器 定义一个类,这个类继承ActionListener pubulic class ButListener implements ActionListener{ Public void actionPerformed(ActionEvent e){ }} 给按钮添加动作监听器方法 ButListener but = new ButListen(); jbu.addActionListener(but); 加上监听机制后再监听器ButListener时间处理方法中再创建窗口即可得到点

  • Java Spring 事件监听详情解析

    目录 前言 需求背景 事件概念 定义 组成 事件实现 时序图 前言 前段时间因为工作的需要用到Spring事件,翻翻文档将功能实现了,但是存在少许理解不畅的地方,今天有空来梳理梳理. 需求背景 叶子同学在新入职公司,老大让他实现登陆功能,叶子随手写完,上线无bug,一切安好 //登陆伪代码 public void login(....){ userLogin(....); } 几天之后,老大说为维护用户的粘度,每天登陆送积分.叶子同学,二话不说,一顿操作后,上线无bug,一切安好 //登陆伪代码

随机推荐