JS--传统事件模型的问题
2014-04-26 19:24
411 查看
事件绑定分为两种情况:传统的事件绑定(内联模型、脚本模型),一种是现代事件绑定模型(DOM2级事件绑定)。
内联模型的事件绑定是将事件写在元素标签中,将事件绑定函数当做元素的一种属性来实现的,这种绑定模型违反了HTML中分层的原则,故不讨论
脚本模型,在单独的JS文件中,通过DOM来获取元素,然后为元素绑定事件等,下面讨论的问题都是用的脚本模型
分别在第一个onload函数之前输出这个函数以及它的类型,发现,在没有定义之前,旧版的火狐输出的是undefined,新版的火狐、IE、谷歌都是null,类型都是object,在定义这儿函数之后,输出的类型都是function,代码段如下:
解决覆盖问题:可以创建一个保存器将它保存下来,然后在下一次注册函数的函数中先执行一次,然后再注册新的函数,利用了JS中没有块级作用域的概念
切换器:在单击这个div的时候,切换样式
上面这个切换器中存在一个问题就是,当在添加一个box.onclick=function(){}; 的时候,被新添加的函数又会被覆盖,
为了解决这个覆盖的问题,可以在上面的新添加的匿名函数中执行后面的事件绑定函数
为了解决上面的三个问题,我们自己写一个事件添加函数
在JS中,数组是集数组、集合与字典一生的类型,对象操作可以使用数组操作来完成,window.onload 相当于window['onload'];
自己手动的写一个事件添加函数:
通过这个事件函数,可以给元素添加多个事件绑定函数。并且都会执行
将这个自定义的事件添加函数用在上面的事件切换器上面去,能够解决被覆盖的问题,但同样要注意this的传值需要我们手动传递。
这种问题同样需要我们手动的去解决判断,比较麻烦,W3C在它的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--传统事件模型的问题
- 关于js中文乱码问题和js事件代理动态生成div
- JS中for循环出现的问题:如何给li元素绑定事件,点击每个li元素弹出对应的索引?
- 原生JS根据元素id调用元素事件无效的问题
- form表单回车提交问题,JS监听回车事件
- 通过SlimerJS触发键盘事件使优酷视频快进(问题未解决)
- ...后台代码中如何调用 javascript 函数的问题! - ASP.NET专题(按钮事件中调用JS文件中函数)
- three.js学习笔记 obj模型加载问题
- js onmousewheel事件多次触发问题解决方法
- JS阻止父层事件(JS冒泡问题)
- js 下拉框change事件变化所引起的问题
- JS 事件处理模型
- js的事件流模型
- js动态给对象onclick事件赋值,动态传参数的问题
- 解决js中新增加的标签无法触发事件的问题
- js-事件-作用域问题
- 【JS】DOM事件模型
- 移动端点击a标签和img标签以及添加的js点击事件时的闪屏问题 解决方案
- js鼠标单击和双击事件冲突问题的解决方法
- js中的事件委托机制(解决动态生成的dom元素无法绑定事件的问题)