事件绑定分为两种情况:传统的事件绑定(内联模型、脚本模型),一种是现代事件绑定模型(DOM2级事件绑定)。

内联模型的事件绑定是将事件写在元素标签中,将事件绑定函数当做元素的一种属性来实现的,这种绑定模型违反了HTML中分层的原则,故不讨论

<span style="font-size:18px;"><div id="box" onclick="alert('abc')">测试DIV</div> </span>

脚本模型,在单独的JS文件中,通过DOM来获取元素,然后为元素绑定事件等,下面讨论的问题都是用的脚本模型

<span style="font-size:18px;">window.onload = function(){
var box = document.getElementById("box");
box.onclick = function(){
alert("box");
}
}</span>
</pre><pre code_snippet_id="314036" snippet_file_name="blog_20140426_3_5927837" class="javascript" name="code"><span style="font-size:18px;"></span><h2><span style="font-size:18px;"><strong>问题一</strong>、一个事件绑定函数被触发多次,导致前面的会被后面的覆盖,以window.onload 为例</span></h2>
<span style="font-size:18px;">	//下面程序端只是输出 "第二次"
window.onload = function(){
alert("第一次");
} window.onload=function(){
alert("第二次");
}</span>

分别在第一个onload函数之前输出这个函数以及它的类型,发现,在没有定义之前,旧版的火狐输出的是undefined,新版的火狐、IE、谷歌都是null,类型都是object,在定义这儿函数之后,输出的类型都是function,代码段如下:

<span style="font-size:18px;">alert(window.onload);	//null	旧版火狐(3.8.6)输出为undefined
alert(typeof window.onload); //object window.onload = function(){
alert("第一次");
} alert(window.onload); //当已经定义了这个函数的时候输出是这个函数的函数体
alert(typeof window.onload); //旧版和新版都是输出的undefined window.onload=function(){
alert("第二次");
}</span>

解决覆盖问题:可以创建一个保存器将它保存下来,然后在下一次注册函数的函数中先执行一次,然后再注册新的函数,利用了JS中没有块级作用域的概念

<span style="font-size:18px;">	window.onload = function(){
alert("第一次");
} //创建一个保存器
if(typeof window.onload == "function"){
var saved = null;
saved = window.onload; //保存上一个事件
} window.onload=function(){
if(typeof saved != "null"){
saved(); //执行上一个事件
}
alert("第二次"); //执行本事件中的内容
}</span>
<span style="font-size:18px;"> 	//上面的保存器中saved就相当于window.onload;saved()就相当于window.onload();但是window.onload后面
  //是不能够直接加括号的,saved相当于注册的匿名函数,匿名函数的自我执行是直接在后面添加一个括号
  //所以 saved() 相当于 windo.onload=function(){};
</span>

问题二、事件切换器(this自动传参以及可读性问题)

页面上有两个样式表

<span style="font-size:18px;">  <style>
.red{
width:200px;
height:200px;
background-color:red;
}
.blue{
width:200px;
height:200px;
background-color:blue;
}
</style></span>
<span style="font-size:18px;"><div id="box">测试DIV</div></span>

切换器:在单击这个div的时候,切换样式

<span style="font-size:18px;">//点击页面上的某个元素,改变他们的背景颜色
window.onload=function(){
var box = document.getElementById("box");
box.onclick = toRed;
} //下面两个函数中 this 如果绑定到了box.onclick 的事件中,this是代表的box对象,在全局代表的是window function toRed(){
this.className = "red";
this.onclick = toBlue;
} function toBlue(){
this.className = "blue";
this.onclick = toRed;
}</span>

上面这个切换器中存在一个问题就是,当在添加一个box.onclick=function(){}; 的时候,被新添加的函数又会被覆盖

<span style="font-size:18px;">window.onload=function(){
var box = document.getElementById("box");
box.onclick = function(){ //被覆盖了,不会被执行
alert("new");
}
box.onclick = toRed;
}</span>

为了解决这个覆盖的问题,可以在上面的新添加的匿名函数中执行后面的事件绑定函数

<span style="font-size:18px;">window.onload=function(){
var box = document.getElementById("box");
box.onclick=function(){
alert("new");
//toBlue(); //通过匿名函数来执行函数的话,里面的this代表的就是window
toBlue.call(this); //通过冒充调用将this传递过去
}
}</span>

为了解决上面的三个问题,我们自己写一个事件添加函数

    在JS中,数组是集数组、集合与字典一生的类型,对象操作可以使用数组操作来完成,window.onload 相当于window['onload'];

<span style="font-size:18px;">	window['onload'] = function(){
alert("onload");
}</span>

自己手动的写一个事件添加函数:

<span style="font-size:18px;">	function addEvent(obj,type,fun){//obj:要添加事件绑定函数的对象,type:事件名,fun:事件执行函数
var saved = null; //保存每次触发的事件处理函数
if(typeof obj[type] == "function"){
saved = obj[type]; //保存上一个事件
} obj[type] = function(){
if(saved){ //如果存在上一个事件,就先执行上一个事件
alert(saved);
saved();
}
fun();
}
}</span>

通过这个事件函数,可以给元素添加多个事件绑定函数。并且都会执行

<span style="font-size:18px;">window.onload=function(){
var box = document.getElementById("box");
addEvent(box,"onclick",function(){alert("第一个");});
addEvent(box,"onclick",function(){alert("第二个");});
addEvent(box,"onclick",function(){alert("第三个");});
}</span>

将这个自定义的事件添加函数用在上面的事件切换器上面去,能够解决被覆盖的问题,但同样要注意this的传值需要我们手动传递。

<span style="font-size:18px;">	function addEvent(obj,type,fun){//obj:要添加事件绑定函数的对象,type:事件名,fun:事件执行函数
var saved = null; //保存每次触发的事件处理函数
if(typeof obj[type] == "function"){
saved = obj[type]; //保存上一个事件
} obj[type] = function(){
if(saved){ //如果存在上一个事件,就先执行上一个事件
saved();
}
fun.call(this); //注意this的作用范围,故要传递进去 }
} window.onload=function(){
var box = document.getElementById("box");
//addEvent(box,"onclick",function(){alert("OK");});
addEvent(box,"onclick",toRed);
} //这和上面通过window.onload的注册时一样的
//addEvent(window,"onload",function(){
/// var box = document.getElementById("box");
/// addEvent(box,"onclick",function(){alert("OK");});
// addEvent(box,"onclick",toRed);
//}); function toRed(){
this.className = "red";
//this.onclick = toBlue;
addEvent(this,"onclick",toBlue);
} function toBlue(){
this.className = "blue";
//this.onclick = toRed;
addEvent(this,"onclick",toRed);
}</span>

问题三、浏览器假死

上面通过我们自定义的函数,解决了传统的事件绑定的缺点,但是上面这个事件切换器,如果在火狐中运行,会发现当我们点击到一定的次数后,浏览器就会卡死。这是因为在我们自己写的这个事件添加函数,其本质是通过递归来实现的,JS中有一种概念叫闭包,它会把变量驻留在内存中,这种概念上和递归是一样的,当递归多次后,内存资源占用过多,导致浏览器假死的现象,而IE中有垃圾回收机制,它会帮我们回收一些资源然后释放,故不存在这种问题。解决这种假死办法就是每次定义之前,删除之前的东西。

<span style="font-size:18px;">	//移除事件处理函数,采用的是一刀切的方法
function removeEvent(obj,type){
if(typeof obj[type] == "function"){
obj[type] = null;
}
}</span>
<span style="font-size:18px;">//调用函数修改为
function toRed() {
this.className = 'red';
removeEvent(this, 'click');
addEvent(this, 'click', toBlue);
}</span>

问题四、不能屏蔽重复注册问题

<span style="font-size:18px;">	addEvent("window","onload",init);	//init是一个函数
addEvent("window","onload",init);
addEvent("window","onload",init);</span>

这种问题同样需要我们手动的去解决判断,比较麻烦,W3C在它的DOM2事件中解决了此问题,解决办法见下一章

JS--传统事件模型的问题的更多相关文章

  1. JS的事件模型

    之前对事件模型还是比较清楚的,许多概念都清晰映射在脑海中.工作之后,一方面使用的局限性,二是习惯于用框架中的各种事件监听方式,简单即方便,久而久之,事件的一些概念开始淡出记忆中,就像我现在已经开始淡忘 ...

  2. js实现事件模型bind与trigger

    function Emitter() { this._listener = [];//_listener[自定义的事件名] = [所用执行的匿名函数1, 所用执行的匿名函数2] } //注册事件 Em ...

  3. js二级事件模型的处理细节

    一.纠正网络上的一个误传--“IE不支持事件捕获” 可以在浏览器中运行上面demo,在各主流浏览器中,鼠标移上都可以分别触发捕获与冒泡事件的监听函数,所以IE也是支持事件捕获的,连IE6都支持,只是在 ...

  4. js 事件模型详解

    把js的事件模型,分为两类,DOM0级和DOM2级, DOM0级 通常直接在DOM对象上绑定函数对象,指定事件类型,dom.onClick = function(){};类似于这种写法,移除事件,则直 ...

  5. js的事件学习笔记

    目录 0.参考 1.事件流 冒泡传播 事件捕获 2.事件绑定--onclick接口 onclick类的接口,只能注册一个同类事件 onclick类的接口,使用button.onclick = null ...

  6. JS事件模型小结

    三种事件模型:原始事件模型(DOM0),DOM2事件模型,IE事件模型: 不同点: 事件程序的注册(给HTML元素所对应的JS对象绑定事件) 事件传播的过程 事件模型的注册: 一.原始事件模型(没有兼 ...

  7. JS的事件绑定、事件流模型

    .t1 { background-color: #ff8080; width: 1100px; height: 40px } 一.JS事件 (一)JS事件分类 1.鼠标事件:click/dbclick ...

  8. javascript中0级DOM和2级DOM事件模型浅析 分类: C1_HTML/JS/JQUERY 2014-08-06 15:22 253人阅读 评论(0) 收藏

    Javascript程序使用的是事件驱动的设计模式,为一个元素添加事件监听函数,当这个元素的相应事件被触发那么其添加的事件监听函数就被调用: <input type="button&q ...

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

     一.JS事件 (一)JS事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresi ...

  10. js事件模型与自定义事件

    JavaScript 一个最简单的事件模型,需要有事件绑定与触发,还有事件删除. var eventModel = { list: {}, bind: function () { var args = ...

随机推荐

  1. 导航控制器(UINavigationController)

    一.导航控制器基础 1.导航控制器的组成 i.中间视图 ii.导航栏 iii.工具栏 2.配置一个导航界面 a.配置一个导航界面最重要的部分就是配置被包含的视图控制器. b.当它所属的视图控制器在导航 ...

  2. IIS安装错误导致网站访问不了

    如下图,网站正常但就是访问不了,原因是IIS配置不正确,把ASP.NET4.5等相关勾选上就可以了,不要用默认的勾选,要自己手动勾选.

  3. javascript变量和对象要注意的点

    js对象和变量,对象本身是没有名称的,之所以使用变量是为了通过某个名称来称呼这样一种不具名称的对象.变量分基本变量和引用类型变量.将基本类型的的值付给变量的话,变量将这个值本身保存起来. <sc ...

  4. php 解决json_encode中文问题

    众所周知使用json_encode可以方便快捷地将对象进行json编码,但是如果对象的属性中存在着中文,问题也就随之而来了.json_encode会将中文转换为unicode编码例如:'胥'经过jso ...

  5. android任意view爆炸效果--第三方开源--ExplosionField

    犹如天女散花一样,爆炸散列,比较有趣.Android ExplosionField在github上的项目主页是:https://github.com/tyrantgit/ExplosionField ...

  6. linux网络子系统内核分析

    1.选择路由 若要将数据包发至PC2,则linux系统通过查询路由表可知168.1.1.10(目的地址)的网关地址为192.168.1.1,此时linux系统选择网卡1发送数据包. 2.邻居子系统(通 ...

  7. Java 控制台执行带自定义包定义的类,出现“Exception in thread "main" java.lang.NoClassDefFoundError: ConnectSQLServer (wrong name: sine/ConnectSQLServer)”

    1.先说明一下代码实现:自定义package sine, 源代码保存路径为:E:\JSP\HibernateDemo\HibernateDemoProject\src\sine\ConnectSQLS ...

  8. hdu 1237 简单计算器

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1237 简单计算器 Description 读入一个只包含 +, -, *, / 的非负整数计算表达式, ...

  9. bash: 避免命令重复执行的简单脚本

    1. 根据命令生成md5做为文件名保存当前进程的pid2. 使用exec执行命令3. 如果再次执行, 使用ps -p检测上次pid是否有效, 如果是则exit 200.否则重复1.hadoop@ubu ...

  10. Java使用FileLock实现Java进程互斥锁

    原理:JDK的nio包中FileLock实现类似Linux fcntl的文件锁, 可使文件被进程互斥访问.  借助此功能, 可以实现强大的Java进程互斥锁, 从而在应用层面保证同一时间只有惟一的Ja ...