zoukankan      html  css  js  c++  java
  • JavaScript移除绑定在元素上的匿名事件处理函数

    前言:

    面试的时候有点蒙,结束之后想想自己好像根本就误解了面试官的问题,因为我理解的这个问题本身就没有意义。但是当时已经有一些思路,但是在一个点上被卡住。

    结束之后脑子瞬间灵光,想出了当时没有迈出的那一小步。所以不想计较这个问题本身的意义,单纯的想要把这个我理解错了的问题解决,就当是满足自己一个小小的愿望吧。

    问题:

    用addEventListener()和attachEvent()给一个DOM元素绑定事件处理程序时,如果传入一个匿名函数,那么用相应的removeEventListener()和detachEvent()是无法将这个匿名的处理程序解除绑定的。所以我们用的时候应该传入一个函数表达式。

    那么,如果我就是想使用匿名函数进行绑定和解绑,怎么解决?

    思路:

    既然这两个函数都高冷的说明了不接受相同的匿名函数进行解绑,那么就只能另寻出路,不能靠它来管理事件了。

    所以需要一个自定义的对象来管理事件。

    事件处理程序的本质就是,当一个事件在一个对象上发生时,执行监听这个事件的函数。

    翻译一下:

    一个DOM元素可能被绑定多个事件类型的处理程序。比如click的时候颜色改变,mouseover的时候变大。

    一个事件类型可能绑定多个事件处理程序。比如mouseover的时候又变色又变大。

    所以,这个事件对象应该有一个属性用来存储这个DOM元素上绑定的所有事件处理程序,还应该有两个方法,一个用来添加,一个用来删除。

    复制代码
    {
    handlers:{
    type1:[handler1,handler2],
    type2:[handler1,handler2],
    ...//其他事件类型和对应的事件处理函数
    },
    on:function(){},
    off:function(){}
    }
    复制代码

    当一个事件发生时,就调用这个对象里面对应的事件类型的数组里面的所有函数。

    所以绑定事件就是往对应的数组里面添加函数,解除绑定事件就是把这个函数从这个数组里面删掉。

    那么怎么保证操作的是那个正确的DOM元素呢?

    显然,每个DOM元素都应该需要一个这样的对象,用于管理自己的事件处理程序。

    每个对象都有的东西,那不就是他的属性嘛。(而我当时就被卡在了这里)。

    实现:

    每个DOM元素都需要这样一个对象,而且每个对象中的on()和off()方法都是相同的,所以需要一个构造函数,把这两个方法放到他的原型对象中去。

    复制代码
    function EventManage(){
      this.handlers={}
    }
    EventManage.prototype={
      on:function(type,handler){
        if(!this.handlers[type]){
          this.handlers[type]=[handler];
          return true;  //避免添加多个事件
        }else{
          this.handlers[type].push(handler);
        }
      },
      off:function(type,handler){
        for(var i=0,len=this.handlers[type].length;i<len;i++){
          if(this.handlers[type][i].toString()==handler.toString()){
            this.handlers[type].splice(i,1);
          }
        }
      }
    }
    复制代码

    每个对象有了这两个方法,就可以自行添加和移除事件处理程序了,但是,监听事件,还是要靠JavaScript提供的方法,所以借用addEventListner()和attachEvent()来监听事件:

    复制代码
    var EventUtil={};
    EventUtil.on=function(ele,type,handler){
      if (!ele.event) {
        ele.event=new EventManage();
      }
      var isNewType=ele.event.on(type,handler);
      var fire=function(){
          for(var i=0,len=ele.event.handlers[type].length;i<len;i++){
            ele.event.handlers[type][i]();
          }
        };
      if (isNewType) {
        if (ele.addEventListener) {
          ele.addEventListener(type,fire,false);
        }else{
          ele.attachEvent("on"+type,fire);
        }
      }
    }
    EventUtil.off=function(ele,type,handler){
      ele.event.off(type,handler);
    }
    复制代码

    这里要注意一个问题,每次使用EventUtil.on()时都会重新定义一个fire函数,addEventListener()就会给相同的事件类型添加多个相同的事件处理程序,所以需要判断一下这个事件类型是不是新增的,如果是的话再用addEventListener()来监听这个事件类型。

    使用示例:

    复制代码
    var btn=document.getElementById("btn");
    
    EventUtil.on(btn,"click",function(){
      console.log("11");
    });
    EventUtil.on(btn,"click",function(){
      console.log("22");
    });
    EventUtil.off(btn,"click",function(){
      console.log("11");
    });
    复制代码

    当点击btn时,只打印了"22",说明匿名函数成功解绑。

  • 相关阅读:
    bzoj1615 [Usaco2008 Mar]The Loathesome Hay Baler麻烦的干草打包机
    bzoj3402 [Usaco2009 Open]Hide and Seek 捉迷藏
    CF B. Planning The Expedition
    Codeforces ~ 1009C ~ Annoying Present (贪心)
    Codeforces Round#498(Div.3)D. Two Strings Swaps
    牛客Another Distinct Values
    牛客多校第四场 G Maximum Mode
    可持化永久树 的 STL ( rope )
    KMP算法 (字符串的匹配)
    求(3+开根5) N次方的整数部分最后3位
  • 原文地址:https://www.cnblogs.com/libin-1/p/6010678.html
Copyright © 2011-2022 走看看