javascript事件绑定学习要点

事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(DOM2级模型)。现代事件绑定在传统绑定上提供了更强大更方便的功能。

一 传统事件绑定的问题

传统事件绑定中的内联模型不做讨论,基本很少去用。先来看一下脚本模型,脚本模型将一个函数赋值给一个事件处理函数。传统绑定如:

window.onload=function(){
 var box=document.getElementById('box');
 box.onclick = function(){
  alert('Lee');
 };
};

问题一:一个事件处理函数触发两次事件

如果一个页面有两个或者多个js,并且第一个js是第一个程序开发的,第二个js是第二个程序员开发的。第一个window.onload被覆盖了,如

window.onload=function(){
 alert('Lee');
};

window.onload=function(){
 alert('Mr.lee');
}

结果只是打印了 Mr.lee

其实是有办法解决这个问题的,看下面这两种形式。
a:

alert(window.onload);//一开始没有注册window.onload,那么就是null

window.onload=function(){
 alert('Lee');
};

alert(window.onload);//如果已经有window.onload,打印的是函数function

window.onload=function(){
 alert('Mr.lee');
}

b:

alert(typeof window.onload);//一开始没有window.onolad,旧版火狐显示undefined,新版显示object,

window.onload=function(){
 alert('Lee');
};

alert(typeof window.onload);//如果已经有window.onload,所有浏览器都会显示function

window.onload=function(){
 alert('Mr.lee');
}

所以解决办法有了。

 window.onload=function(){
 alert('Lee');
};

if(typeof window.onload=='function'){
 var saved=null;//保存上一个事件对象
 saved=window.onload;
}

//saved 就是window.onload,saved()相当于window.onload(),但是window.onload()不能执行的
//所以saved()相当于window.onload=function(){}

window.onload=function(){
 if(saved){
  saved();//执行上一个事件 window.onload=function(){}
 }
 alert('Mr.lee'); //执行本事件
}

问题二:事件切换器
切换一个id为box的div,让里面的背景red与blue直接切换,并且切换之前弹框一次,如:

window.onload=function(){
 var box=document.getElementById('box');
 box.className="red";
 box.onclick=function(){
  alert('Lee'); //只执行了一次
  blue.call(this);//通过匿名函数执行某一函数,那么里面的this就是代表的window,所以可以通过call传递
 };
}

function blue(){
 this.className="blue";
 this.onclick=red;

}

function red(){
 this.className="red";
 this.onclick=blue;
}

上面的代码虽然实现了切换功能,但是弹框只执行了一次。

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }

}
addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 addEvent(box,'click',red);
}

//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉

按照上面的代码出现了注释中的错误,解决的办法如下:

//添加事件函数
//obj相当于window
//type相当于onload
//fn相当于function(){}
function addEvent(obj,type,fn){
 //用于保存上一个事件
 var saved=null;
 if(typeof obj['on'+type]=='function'){
  saved=obj['on'+type];//保存上一个事件
 }
 obj['on'+type]=function(){
  if(saved){
   saved();
  }
  fn.call(this);
 }

}

//当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归
//因为积累了太多的保存的事件
//解决方案,就是用完的事件,就立刻移除掉

//移除事件函数
function removeEvent(obj,type){
 if(obj['on'+type]){
  obj['on'+type]=null;
 }
}

addEvent(window,'load',function(){
 var box=document.getElementById("box");
 //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖
 // alert('ss');
 //});
 addEvent(box,'click',blue);
});

function red(){
 this.className="red";
 removeEvent(this,'click');
 addEvent(box,'click',blue);
}

function blue(){
 this.className="blue";
 removeEvent(this,'click');
 addEvent(box,'click',red);
}

二 W3C事件处理函数
addEventListener()与removeEventListener()
W3C事件处理函数两个,addEventListener()与removeEventListener()。

//W3C自带的两个添加事件和删除事件
1.覆盖问题,解决

window.addEventListener('load',function(){
 alert('Lee');
},false);

window.addEventListener('load',function(){
 alert('Mr.Lee');
},false);

window.addEventListener('load',function(){
 alert('Mrs.Lee');
},false);

2.相同函数屏蔽的问题,解决

window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
function init(){
 alert('Lee');
}

3.是否可以传递this,解决
例子1:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert(this);
 },false);
},false);

例子2:

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',blue,false);
},false);

function red(){
 this.className="red";
 this.removeEventListener('click',red,false);
 this.addEventListener('click',blue,false);
}

function blue(){
 this.className="blue";
 this.removeEventListener('click',blue,false);
 this.addEventListener('click',red,false);
}

4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决

window.addEventListener('load',function(){
 var box=document.getElementById('box');
 box.addEventListener('click',function(){
  alert('Lee');
 },false);
 box.addEventListener('click',blue,false);
},false);

综上所述:W3C是比较完美的解决了这些问题,非常好用,但是IE8和之前的浏览器并不支持,而是采用了自己的事件,当然IE9已经完全支持了W3C的这两个事件处理函数。

W3C可以设置冒泡和捕获方式。

支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。
事件的传播是可以阻止的:
在W3c中,使用stopPropagation()方法
在IE下设置cancelBubble = true;

三.IE事件处理函数

attachEvent()和detachEvent()
IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的参数:事件名称和函数。

在使用这两组函数的时候,先把区别说一下:1.IE不支持捕获,只支持冒泡;2.IE添加事件不能屏蔽重复的函数;3.IE中的this指向的是window而不是DOM对象。4.在传统事件上,IE是无法接受到event对象的,但使用了attchEvent却可以,但有些区别。

1.覆盖问题,解决了,但有不同,结果是Mrs.Lee,Mr.Lee,最后是Lee

window.attachEvent('onload',function(){
 alert('Lee');
});

window.attachEvent('onload',function(){
 alert('Mr.Lee');
});
window.attachEvent('onload',function(){
 alert('Mrs.Lee');
});

2.相同函数屏蔽的问题,未解决。

window.attachEvent('onload',init);
window.attachEvent('onload',init);

function init(){
 alert('Lee');
}

3.是否可以传递this,不能,this指的是window。需要用call方法。

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',function(){
  //alert(this===box);
  alert(this===window); //true
 });
});

下面还有办法就是通过window.event.srcElement。代码如下:

window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.attachEvent('onclick',blue);
});

function red(){
 var that=window.event.srcElement;
 that.className="red";
 that.detachEvent('onclick',red);
 that.attachEvent('onclick',blue);
}

function blue(){
 var that=window.event.srcElement;
 that.className="blue";
 that.detachEvent('onclick',blue);
 that.attachEvent('onclick',red);
}

4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决。

在传统绑定上,IE是无法像W3C那样通过传参接受event对象,但是使用attachEvent()却可以。

 window.attachEvent('onload',function(){
 var box=document.getElementById('box');
 box.onclick=function(evt){ //传统方法IE无法通过参数获取evt
  alert(evt);//undefined
 }
 box.attachEvent('onclick',function(evt){
  alert(evt);//object
  alert(evt.type);//click
  alert(evt.srcElement.tagName);//DIV
  alert(window.event.srcElement.tagName);//DIV
 });
});

跨浏览器的兼容

跨浏览器添加事件

function addEvent(obj,type,fn){
 if(obj.addEventListener){
  obj.addEventListener(type,fn,false);
 }else if(obj.attachEvent){
  obj.attachEvent('on'+type,fn);
 }
}

跨浏览器移除事件

function removeEvent(obj,type,fn){
 if(obj.removeEventListener){
  obj.removeEventListener(type,fn,false);
 }else if(obj.detachEvent){
  obj.detachEvent('on'+type,fn);
 }
}

跨浏览器获取目标对象

function getTarget(evt){
 if(evt.target){
  return evt.target;
 }else if(window.event.srcElement){
  return window.event.srcElement;
 }
}

调用方式:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'click',blue);
});

function red(evt){
 var that=getTarget(evt);
 that.className="red";
 removeEvent(that,'click',red);
 addEvent(that,'click',blue);
}

function blue(evt){
 var that=getTarget(evt);
 that.className="blue";
 removeEvent(that,'click',blue);
 addEvent(that,'click',red);
}

四.事件对象的其他补充

relatedTarget事件

w3c中的一个relatedTarget事件。
例如:

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(evt){
  alert(evt.relatedTarget); //得到移入box最近的那个DOM对象
 });

 addEvent(box,'mouseout',function(evt){
  alert(evt.relatedTarget); //从box移出最近的那个DOM对象
 });
});

IE提供了两组分别用于移入移出的属性fromElement和toElement,分别对应mouseover和mouseout。

addEvent(window,'load',function(){
 var box=document.getElementById('box');
 addEvent(box,'mouseover',function(){
  alert(window.event.fromElement.tagName); //得到移入box最近的那个DOM对象
 });

 addEvent(box,'mouseout',function(){
  alert(window.event.toElement.tagName); //从box移出最近的那个DOM对象
 });
});

PS:fromElement和toElement如果分别对应相反的鼠标事件,没有任何意义。

剩下要做的就是跨浏览器兼容操作:

function getTarget(evt){
 var e=evt || window.event;
 if(e.srcElment){ //IE
  if(e.type=='mouseover'){
   return e.fromElement.tagName;
  }else if(e.type="mouseout"){
   return e.toElement.tagName;
  }
 }else if(e.relatedTarget){ //w3c
  return e.relatedTarget;
 }
}

屏蔽跳转操作

取消事件的默认行为有一种不规范的做法,就是返回false。

link.onclick=function(){
 alert('Lee');
 return false;
}

PS:虽然return false;可以实现这个功能,但是有漏洞。
第一:必须写到最后,这样导致中奖的代码执行后,有可能执行不到return false;
第二:return false 写到最前那么之后的自定义操作就失效了。
所以最好的办法应该是在最前面就阻止默认行为,并且后面的代码还可以执行。

link.onclick=function(evt){
 evt.preventDefault;//w3c,阻止默认行为
 alert('Lee');
}

link.onclick=function(evt){
 window.event.returnValue=false;//IE,阻止默认行为
 alert('Lee');
}

那么跨浏览器的兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}

右键菜单contextmenu
兼容:

function preDef(evt){
 var e=evt || window.event;
 if(e.preventDefault){
  e.preventDefault();
 }else{
  e.returnValue=false;
 }
}

addEvent(window,"load",function(){
 var body=document.getElementsByTagName('body')[0];
 addEvent(body,'contextmenu',function(evt){
  preDef(evt);
 })
});

PS:contextmenu事件很常用,这直接导致浏览器兼容性较为稳定。

卸载前事件:beforeunload
这个事件可以帮助在离开本页的时候给出相应的提示,“离开”或者“返回”操作。

addEvent(window,'beforeonload',function(){
 preDef(evt);
});

鼠标滚轮(mousewheel)和DOMMouseScroll
用于获取鼠标上下滚轮的距离

addEvent(document,'mousewheel',function(evt){ //非火狐
 alert(getWD(evt));
});

addEvent(document,'DOMMouseScroll',function(evt){ //火狐
 alert(getWD(evt));
});

function getWD(evt){
 var e=evt|| window.event;
 if(e.wheelDelta){
  return e.wheelDelta;
 }else if(e.detail){ //火狐
  return -evt.detail*30;
 }
}

PS:通过浏览器检测可以确定火狐只执行DOMMouseScroll。

DOMContentLoaded事件和readystatechange事件

DOMContentLoaded事件和readystatechange事件,有关DOM加载方面的事件。

(0)

相关推荐

  • 浅谈JavaScript事件绑定的常用方法及其优缺点分析

    传统方式  element.onclick = function(e){ // ... };  1.  传统绑定的优点 非常简单和稳定,可以确保它在你使用的不同浏览器中运作一致 处理事件时,this关键字引用的是当前元素,这很有帮组 2. 传统绑定的缺点 传统方法只会在事件冒泡中运行,而非捕获和冒泡 一个元素一次只能绑定一个事件处理函数.新绑定的事件处理函数会覆盖旧的事件处理函数 事件对象参数(e)仅非IE浏览器可用 W3C方式  element.addEventListener('click'

  • js添加绑定事件的方法

    先介绍js添加事件通用方法,具体内容如下 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <p id="p1">测试添加事件:firefox使用addEventListener,ie使用attachEvent<br> 点击此p标签

  • 浅析js绑定事件的常用方法

    浅析js绑定事件的常用方法  <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http:

  • 关于JavaScript中事件绑定的方法总结

    最近收集了一些关于JavaScript绑定事件的方法,汇总了一下,不全面,但是,希望便于以后自己查看. JavaScript中绑定事件的方法主要有三种: 1 在DOM元素中直接绑定 2 JavaScript代码中直接绑定 3 绑定事件监听函数 一.在DOM元素中直接绑定 也就是直接在html标签中通过 onXXX="" 来绑定.举个例子: <input type="button" value="点我呦" onclick="aler

  • 详解javascript事件绑定使用方法

    由于html是从上至下加载的,通常我们如果在head部分引入javascript文件,那么我们都会在javascript的开头添加window.onload事件,防止在文档问加载完成时进行DOM操作所出现的错误.如果有多个javascript文件,那么极有可能出现多个window.onload事件,但是最后起作用的只有一个,这时候就需要使用事件绑定来解决这个问题了. IE方式 attachEvent(事件名称, 函数),绑定事件处理函数 detachEvent(事件名称, 函数),解除绑定 DO

  • javascript事件绑定学习要点

    事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(DOM2级模型).现代事件绑定在传统绑定上提供了更强大更方便的功能. 一 传统事件绑定的问题 传统事件绑定中的内联模型不做讨论,基本很少去用.先来看一下脚本模型,脚本模型将一个函数赋值给一个事件处理函数.传统绑定如: window.onload=function(){ var box=document.getElementById('box'); box.onclick = function(){ alert('Le

  • javaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序整理总结

    抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享. (一)事件绑定的几种方式 javascript给DOM绑定事件处理函数总的来说有2种方式:在html文档中绑定.在js代码中绑定.下面的方式1.方式2属于在html中绑定事件,方式3.方式4和方式5属于在js代码中绑定事件,其中方法5是最推荐的做法. 方式1: HTML的DOM元素支持onclick.onblur等以on开头属性,我们可以直接在这些属性值中编写javascript代码.当点击div的时候,

  • 整理Javascript事件响应学习笔记

    什么是事件 JavaScript 创建动态页面.事件是可以被 JavaScript 侦测到的行为. 网页中的每个元素都可以产生某些可以触发 JavaScript 函数或程序的事件.  1.鼠标单击事件(onclick) onclick是鼠标单击事件,当在网页上单击鼠标时,就会发生该事件.同时onclick事件调用的程序块就会被执行,通常与按钮一起使用. 例:我们单击按钮时,触发 onclick 事件,并调用两个数和的函数add2(). <html> <head> <scrip

  • JavaScript 事件绑定及深入

    事件绑定分为两种: 一种是传统事件绑定(内联模型/脚本模型);上一章内容; 一种是现代事件绑定(DOM2级模型);现代事件绑定在传统事件绑定基础上提供了更强大的功能; 一 传统事件绑定的问题 // 脚本模型将一个函数赋值给一个事件处理函数; var box = document.getElementById('box'); // 获取元素; box.onclick = function(){ // 元素点击触发事件; alert('Lee'); } // 问题一:一个事件处理函数触发两次事件;

  • JavaScript组合模式学习要点

    组合模式:将一组对象组合成树形结构,并统一对待组合对象和叶对象,忽略它们之间的不同(因为叶对象也可以也可以包含叶对象而成为组合对象),组合模式中的对象只能是一对多的关系,不能出现多对一. 基本单元:一个组合对象包含多个叶对象.每个基本单元又可以是别的组合对象的叶对象类似文件夹与它里面的内容的关系网,一个文件夹或文件又可以是其它文件夹的内容,但一个文件夹或文件不能同时属于多个上级文件夹. 在JavaScript中实现组合模式时,要保证组合对象和叶对象拥有相同的接口方法,对同一组叶对象的操作必须具有

  • javascript 事件绑定问题

    子页面HTML: 复制代码 代码如下: <input type="checkbox" name="check" onclick="CheckedBox(this)" value="a" /> 子页面JS: 复制代码 代码如下: function CreateIOC(text,value) { var o = document.createElement("a"); o.id = value; o

  • JQuery中DOM事件绑定用法详解

    本文实例讲述了JQuery中DOM事件绑定用法.分享给大家供大家参考.具体分析如下: 在文档加载完成后,如果打算为元素绑定事件来完成某些操作,则可以使用bind()方法来对匹配元素进行特定事件的绑定,bind()方法的调用格式为: bind( type [, data] , fn); bind()方法有3个参数,说明如下. 第1个参数是事件类型,类型包括:blur.focus.load.resize.scroll.unload.click.dblclick.mousedown.mouseup.m

  • 深入理解JS的事件绑定、事件流模型

     一.JS事件 (一)JS事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresize/onchange/onfoucs/onscroll 3.键盘事件: keydown:键盘按下时触发  keypress:键盘按下并抬起的瞬间触发.  keyup:键盘抬起触发 [注意事项] ①执行顺序:keydown keypress keyup ②keypress只能捕获数字,字母,符号键,

随机推荐