改变attachEvent的this指向,导致无法detachEvent的解决方法。
我们在给dom元素绑定事件的时候,通常使用下面的方法:
- //绑定
- function bind(obj,name,fn){
- if(obj.addEventListener){
- obj.addEventListener(name,fn,false);
- }else if(obj.attachEvent){
- obj.attachEvent(‘on’+name,fn);
- };
- };
- //移除
- function unbind(obj,name,fn){
- if(obj.removeEventListener){
- obj.removeEventListener(name,fn);
- }else if(obj.detachEvent){
- obj.detachEvent(‘on’+name,fn);
- };
- };
看似完美,其实在IE8以下中有bug,当在用attachEvent给元素添加事件的时候,默认的this指向是window,而不是元素自身。可以点击下面的div查看。在IE8及以下,this指的是window对象。
- var dom = document.getElementById(‘add_ev’);
- bind(dom,’click’,fn);
- function fn(){
- alert(this)
- };
点击我
然后我们使用call来改变this指向,用bind也可以,只是bind不支持ie9以下。于是绑定函数改成下面这样。
- //绑定
- function bind(obj,name,fn){
- if(obj.addEventListener){
- obj.addEventListener(name,fn,false);
- }else if(obj.attachEvent){
- obj.attachEvent(‘on’+name,function(){
- fn.call(obj)
- });
- };
- };
IE中测试没问题,this不再指向window,而指向了自身;但是新问题又来了,使用call,相当于使用了匿名函数,导致detachEvent无法移除事件了,具体点击下面的div,然后点击移除按钮,会发现在IE8以下,无法移除。
- var dom = document.getElementById(‘add_ev1’);
- bind(dom,’click’,fn);
- function fn(){
- alert(this);
- };
- var del = document.getElementById(‘del_ev1’);
- del.onclick = function () {
- unbind(dom,’click’,fn);
- };
点击我
移除事件
想要解决这个问题也很简单,有两种方法,一种是在dom上挂载一个属性,另外一种在bind的函数里把call单独拎出来,然后return出去给一个变量。具体请在IE8以下浏览器测试。其他浏览器会看不出效果。
方法一,将bind修改为以下:
- //绑定
- function bind(obj,name,fn){
- var _fn = fn;
- fn = function(e){
- _fn.call(obj,e);
- };
- obj.addEventListener? obj.addEventListener(name, fn, false):obj.attachEvent(‘on’+name,fn);
- return fn;
- };
- var dom = document.getElementById(‘add_ev2’);
- //将绑定的赋值给一个变量
- var newFn = bind(dom,’click’,fn);
- function fn(){
- alert(this);
- };
- var del = document.getElementById(‘del_ev2’);
- del.onclick = function () {
- //移除的时候,fn函数写这个变量
- unbind(dom,’click’,newFn);
- };
点击我
移除事件
方法二,将bind和unbind分别修改如下:
- function bind(obj,name,fn){
- if(obj.addEventListener){
- obj.addEventListener(name,fn,false);
- }else if(obj.attachEvent){
- obj[‘new‘+name] = obj[‘new‘+name] || {};
- obj[‘new‘+name][‘new‘+fn] = obj[‘new‘+name][‘new‘+fn] || function(){
- fn.call(obj);
- };
- obj.attachEvent(‘on’+name,obj[‘new‘+name][‘new‘+fn]);
- };
- };
- function unbind(obj,name,fn){
- if(obj.removeEventListener){
- obj.removeEventListener(name,fn);
- }else if(obj.detachEvent){
- if( obj[‘new‘+name] && obj[‘new‘+name][‘new‘+fn]){
- obj.detachEvent(‘on’+name , obj[‘new‘+name][‘new‘+fn]);
- };
- };
- };
点击我
移除事件