学习要点:
1.传统事件绑定的问题
2.W3C事件处理函数
3.IE事件处理函数
4.事件对象的其他补充
事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(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加载方面的事件。
js事件绑定及深入的更多相关文章
-
原生JS事件绑定方法以及jQuery绑定事件方法bind、live、on、delegate的区别
一.原生JS事件绑定方法: 1.通过HTML属性进行事件处理函数的绑定如: <a href="#" onclick="f()"> 2.通过JavaS ...
-
js事件绑定细节说明
javascript绑定事件: 经常用jQuery去写,时间长了对原生态的js事件绑定的知识会慢慢淡化或者遗忘了,必须翻出来再次总结,今天再次把js原生态事件的处理做个总结. 从最初开始,谁刚接触ja ...
-
js事件绑定的几种方式与on()、bind()的区别
版权声明:本文为博主原创文章,未经博主允许不得转载 一直不是很理解几种js事件绑定之间的区别与联系,今天百度了一下,在此做一总结: 1.如果只是简单的绑定一个事件,可以直接写在行内,点击执行一个函数, ...
-
js课程 5-13 js事件绑定和鼠标事件注意事项有哪些
js课程 5-13 js事件绑定和鼠标事件注意事项有哪些 一.总结 一句话总结:js代码的灵魂就是改变标签的属性和样式,就这两种. 1.js触发改的东西是哪两样? 属性和样式 2.js如何让页面用标 ...
-
js 事件绑定
事件绑定的方式 1. DOM 元素行内绑定 <div onclick="alert(1)"></div> 2. js on+eventType do ...
-
js事件绑定函数
js中事件绑定方法大致有三种: 1.在DOM元素中绑定 <input onclick="alert('在DOM中绑定')" type="button" v ...
-
js事件绑定的几种方式
在JavaScript中,有三种常用的绑定事件的方法: 在DOM元素中直接绑定: 在JavaScript代码中绑定: 绑定事件监听函数 一. 在DOM元素中直接绑定 这里的DOM元素,可以理解为HTM ...
-
js事件绑定/监听
事件绑定/监听的方法 1.直接绑定 顾名思义,直接在DOM元素上绑定onclick.onmouseover.onmouseout.onmousedown.onmouseup.ondblclick.on ...
-
原生js事件绑定
一.JS事件 (一)JS事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresiz ...
随机推荐
-
Vim自动补全神器–YouCompleteMe
YouCompleteMe的特别之处 基于语义补全 总所周知,Vim是一款文本编辑器.也就是说,其最基础的工作就是编辑文本,而不管该文本的内容是什么.在Vim被程序员所使用后,其慢慢的被肩负了与IDE ...
-
python是一个解释器
python是一个解释器 利用pip安装python插件的时候,观察到python的运作方式是逐步解释执行的 适合作为高级调度语言: 异常的处理以及效率应该是主要的问题
-
ASP.NET WEB API 中的路由调试与执行过程跟踪
路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...
-
solr4.5分组查询、统计功能介绍
说到分组统计估计大家都不会陌生,就是数据库的group by语句,但是当我们采用solr4.5全文检索时,数据库提供再好的sql语句都没有任何的意义了,那么在solr4.5中我们如何做到分组统计呢?其 ...
-
centos 7用ss命令来查看端口占用和对应进程
mysqld进程在监听4567端口,进程id是2593:# ss -lnp|grep 4567tcp LISTEN 0 128 *:456 ...
-
JavaScript中数组类型的属性和方法
除了Object,Array类型应该是ECMAScript中最常用的类型了. ECMAScript的数组虽然也是数据的有序列表,但还是与其他语言中的数组有很大的区别.比如ECMAScript数组每一项 ...
-
Snail’s trouble
Snail’s trouble Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
-
这些工具对html5开发有很大帮助
如今H5已经在IT这块很热门,所以也就有越来越多的人自学或是报名培训班学习H5,今天写一篇关于当下html5开发工具有哪些?哪个更好一些? 浅谈2017年html5开发工具哪个好: 1.Adobe D ...
-
01安装Python虚拟环境
链接 一,为什么安装虚拟环境? 如果你有0.1版本的Flask已经完成项目,此时Flask1.1版本出来的时候就会对0.1有影响,我们通过虚拟环境可以做到互补影响. 二,安装方法 cmd--pip-- ...
-
kindEditor 富文本编辑器 使用介绍
第一版:存放位置: ---->把该创建的文件包放到javaWeb 过程的 WEB_INF 下:如图所示. 第二步:< kindEditor 插件的引用> :JS引用 <scr ...