`
习惯在马桶上思考
  • 浏览: 114871 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

解决attachEvent中this指向问题

阅读更多

转自http://www.men-ideal.com/archives/441

给dom元素绑定事件监听,很easy,即使刚入门的javascript编程人员都可以办到,比如obj.onclick = fn就可以很轻松的监听obj的单击事件,这固然是没有问题的,但是问题就在于在这个监听过程中,很难触发N个代码片段,例如:

  1. obj.onclick = fn1;
  2. obj.onclick = fn2;
  3. ...

事实上,如果这么做,fn2会把fn1覆盖,也就是说在单击obj时只会执行fn2中的代码片段,fn1则会被忽略,很显然这样不能满足我们的需 求。在考虑到这个问题的时候,JS已经为我们准备了像attachEvnet、addEventListener这样的方法来满足我们的需求,虽然在不同 级别的浏览器中方法不尽相同,利用对browser的能力检测还是可以轻松的实现一个兼容的方法:

  1. function bindEvent(elem,type,fn){
  2.     if(elem.attachEvent){
  3.         elem.attachEvent("on"+type,fn);
  4.     }else{
  5.         elem.addEventListener(type,fn,false);
  6.     }
  7. }
  8. //调用
  9. bindEvent(obj,"click",fn1);
  10. bindEvent(obj,"click",fn2);
  11. bindEvent(obj,"mouseover",function(){alert(this)})   //this->window

这样目的就达到了,当单击obj时,依次执行fn1、fn2。解决了这个问题后,细心的淫们会发现在执行的function中this执行是有问题 的,始终指向window,又不是一个不小的麻烦。那么有没有办法,来解决这个棘手的问题呢,答案是肯定的,这正是我写这篇文章的意义所在,废话!
其实只需对bindEvent稍作加工即可,如下:

  1. function bindEvent(elem,type,fn){
  2.     if(elem.attachEvent){
  3.         elem.attachEvent("on"+type,function(){
  4.             fn.apply(elem,arguments);
  5.         });
  6.     }else{
  7.         elem.addEventListener(type,fn,false);
  8.     }
  9. }
  10. bindEvent(obj,"mouseover",function(){alert(this)})  //this->elem

理论上,这样的解决方案近乎完美了,但是还有一个问题亟待解决,因为在attachEvent中使用了匿名函数来执行fn,导致在无法使用 detachEvent来删除绑定的某个代码片段,也许obj["on"+type] = null可以解决,清空绑定的代码片段,这很粗暴邪恶,同时也违背我们的业务需求。

我想要从根本上解决这些问题,就一定抛弃attachEvent这个方法,事实上我也是这样做的,如下:

  1. //绑定事件
  2. function bindEvent(elem,type,fn){
  3.     if(elem.attachEvent){
  4.         var typeRef = "_" + type;
  5.         if(!elem[typeRef]){
  6.             elem[typeRef] = [];
  7.         }
  8.         for(var i in elem[typeRef]){
  9.             if(elem[typeRef][i] == fn){
  10.                 return;
  11.             }
  12.         }
  13.         elem[typeRef].push(fn);
  14.         elem["on"+type] = function(){
  15.             for(var i in this[typeRef]){
  16.                 this[typeRef][i].apply(this,arguments);
  17.             }
  18.         }   
  19.     }else{
  20.         elem.addEventListener(type,fn,false);
  21.     }
  22. }
  23.  
  24. //移除事件绑定
  25. function removeEvent(elem,type,fn){
  26.     if(elem.detachEvent){
  27.         if(elem["_"+type]){
  28.             for(var i in elem["_"+type]){
  29.                 if(elem["_"+type][i] == fn){
  30.                     elem["_"+type].splice(i,1);
  31.                     break;
  32.                 }
  33.             }
  34.         }
  35.     }else{
  36.         elem.removeEventListener(type,fn,false);
  37.     }
  38. }

这段代码有点饶人,首先根据type类型给elem注册一个相关的属性_type,来存放elem同种类型事件要执行的代码片段,当然在这个过程中 要先判断这个属性是否已经存在,如果存在,则跳过这一步。然后要遍历这个存放代码片段的数组,判断是否有和要添加的代码片段相同的代码片段,如果有,直接 跳出function。假设在上一步条件不满足的情况下(即代码片段不重复),那么把这个代码片段push到相应的数组中。之后干的事情,我想大家应该很 清楚了,没错,就是把相应数组里的代码片段依次apply到elem下执行。当然,这个过程只有在触发事件的时候,才会发生。

依照这个原理,那么要删除绑定的某个代码片段就很容易做到了,只需要从elem["_"+type]这个数组中把相应的代码片段删除即可。

解释一下为什么这个存放需要绑定代码片段的数组设置为elem的一个属性,其实理由很简单,就是不用声明一个全部变量(数组类型),来管理这个二维 的数据结构,这样可以保证bindEvent,removeEvent的高度独立性。

分享到:
评论

相关推荐

    解决使用attachEvent函数时,this指向被绑定的元素的问题的方法

    ### 解决使用attachEvent函数时,this指向被绑定的元素的问题的方法 在Web开发中,尤其是在处理Internet Explorer(IE)浏览器兼容性问题时,我们经常会遇到`attachEvent`函数中的`this`指向问题。默认情况下,`...

    addEventListener和attachEvent二者绑定的执行函数中的this不相同

    2. **`attachEvent`**: 与`addEventListener`不同,`attachEvent`在IE中执行事件处理函数时,`this`会指向绑定事件的元素,通常是全局对象`window`。当点击`test1`时,所有浏览器的行为一致,因为`onclick`属性直接...

    如何解决attachEvent函数时,this指向被绑定的元素的问题?

    然而,与W3C标准的`addEventListener`不同,`attachEvent`的一个显著问题是:在事件处理函数内部,`this`关键字并不指向触发事件的元素,而是指向全局对象(通常是`window`)。这在进行事件处理时可能会引发问题,...

    如何使用Javascript中的this关键字

    在IE浏览器中,使用`attachEvent`方法绑定事件,`this`会指向`window`。而在DOM标准的`addEventListener`中,`this`会指向事件绑定的目标元素。 1. `attachEvent`示例: ```javascript var div1 = document....

    讲两件事:1.this指针的用法小探. 2.ie的attachEvent和firefox的addEventListener在事件处理上的区别

    // 这里,this指向gorush对象 document.onclick = function() { alert(this === document); // true,因为事件监听器是添加到document上的 } ``` 然而,当函数作为回调或匿名函数使用时,`this`的指向可能会发生...

    JavaScript通过attachEvent和detachEvent方法处理带参数的函数

    这是因为attachEvent在绑定事件时会把事件处理函数中的this上下文指向全局对象window,而不是事件触发的那个DOM元素。 处理带参数的函数时,我们通常需要通过创建一个闭包(或者使用匿名函数包装器)来确保事件处理...

    js学习总结之DOM2兼容处理this问题的解决方法

    总的来说,这个`bind`和`unbind`函数组合提供了一种兼容性解决方案,使得在不同浏览器中可以一致地处理事件和`this`的指向问题。在实际应用中,这样的封装可以帮助开发者避免因浏览器差异带来的困扰,提高代码的可...

    JavaScript中的this实例分析

    因此,在JavaScript中,函数内部的this指向谁,并不是由函数自身决定,而是由函数被调用的方式决定的。 Demo2通过new操作符创建函数a的实例,展示了this在构造函数中的指向。使用new操作符创建对象时,构造函数内的...

    attachEvent的使用方法与传递参数[IE|firefox]|angluo-javascript-37392.pdf

    在`attachEvent`中,事件处理函数的执行上下文(即`this`的值)会指向调用`attachEvent`的元素,而不是像`addEventListener`那样默认指向事件的目标元素。此外,`attachEvent`的第二个参数是一个函数,该函数通常...

    js中this的用法实例分析

    实例4说明了在不同的浏览器中,如何使用addEventListener和attachEvent来添加事件监听器,并通过call方法设置正确的this指向。 ```html window.onload = function() { var hi = document.getElementById('hi');...

    JAVASCRIPT THIS详解 面向对象

    然而,在旧版IE浏览器中,使用`attachEvent`时`this`指向`window`对象,这是因为`attachEvent`是作为全局函数而非方法调用的。为了在所有浏览器中保持一致性,可以使用`event.srcElement`来代替`this`获取触发事件的...

    IE6用setAttribute添加事件无效

    // 模拟事件冒泡,确保this指向元素本身 }); } else { throw new Error('Unsupported browser'); } } var myElement = document.getElementById('myElement'); addEvent(myElement, 'click', function() { ...

    js中DOM事件绑定分析.docx

    而在Internet Explorer中,对应的API是`attachEvent`和`detachEvent`,它们不支持事件捕获,且存在其他差异,比如`this`指向问题和重复绑定的问题。 **注意事项**: - **事件冒泡与捕获**:事件通常从最深的节点...

    JavaScript 45 道面试题及答案.docx

    This 总是指向函数的直接调用者(而非间接调用者),如果有 new 关键字,this 指向 new 出来的那个对象,在事件中,this 指向触发这个事件的对象,特殊的是,IE 中的 attachEvent 中的 this 总是指向全局对象 Window...

    JavaScript 45道面试题和答案.docx

    在new构造函数中,this指向新创建的对象;在事件处理中,this指向触发事件的元素。 6. **事件模型**: - 事件冒泡:事件从子元素开始,逐级向上传播到父元素。 - 事件捕获:事件从父元素开始,逐级向下传播到子...

Global site tag (gtag.js) - Google Analytics