JS DOM2级事件兼容处理

DOM2级事件兼容处理

THIS问题

bindDOM2():

在IE6~8中使用attachEvent绑定事件的时候,因为不支持bind方法,所以不能用bind方法解决。

 var tempFn = function () {
          eventFn.call(curEle);
};

通过在外层包括一个化妆函数,调用这个化妆函数时调用需要绑定的函数.call(curEle),并为这个化妆函数增加一个photo属性用于保存化妆之前的函数,便于删除的时候对比函数。

tempFn.photo = eventFn;

为当前元素创建一个自定义属性“myBind”+ evenType,它保存当前元素对应事件类型绑定的化妆函数,以便后期清除。

if (!curEle["myBind" + evenType]) {
          curEle["myBind" + evenType] = [];
        }
        curEle["myBind" + evenType].push(tempFn);
        curEle.attachEvent("on" + eventType, tempFn);

unbindDOM2():

通过当前元素的“myBind”属性找到绑定的化妆函数,对比化妆函数.photo确定是不是这个要移除这个化妆后的函数,找到后把事件和化妆函数移除掉。

 var ary = curEle["myBind" + evenType];
        for (var i = 0; i < ary.length; i++) {
          if (ary[i].photo === eventFn) {
            ary.splice(i, 1);
            curEle.detachEvent("on" + evenType, ary[i]);
            break;
          }
        }

重复问题

bindDOM2():

上面实现的bindDOM2(),可以想同一个元素中同一个行为添加相同的事件函数,存在重复问题。

每一次自己在往自定义属性对应的容器中添加前,看一下之前是否已经有了,有的话就不用再重新的添加了,同理也不需要再往事件池中存储了

var ary = curEle["myBind" + eventType];
        for (var i = 0; i < ary.length; i++) {
          var cur = ary[i];
          if (cur.photo === eventFn) {
            return;
          }
        }

unbindDOM2():

顺序问题

bindDOM2():

不用浏览器自带的事件池,而是自己模拟标准浏览器的事件池
自己创建一个事件池,把需要触发的函数按顺序放到事件池中。为当前元素绑定一个run方法,当run方法执行的时候去事件池中获取同类型的方法数组。然后依次执行这些方法,执行的时候使用call(HTMLElement,e)使THIS指向触发元素,使方法的一个参数变为处理后的window.event。

// run: 我们只给当前元素的带年纪行为绑定一个方法run,当点击事件执行的时候执行的是run方法,我在run方法中根据自己存储的方法顺序分别的再把这些方法执行
      function run(e) {
        e = e || window.event;
        var flag = e.target ? true : false; // IE6~8下不兼容e.target,得到的flag为false
        if (!flag) {
          e.target = e.srcElement;
          e.pageX =
            e.clientX +
            (document.documentElement.scrollLeft || doucment.body.scrollLeft);
          e.pageY =
            e.clientY +
            (document.documentElement.scrollTop || doucment.body.scrollTop);
          e.preventDefault = function () {
            e.returnValue = false;
          };
          e.stopPropagation = function () {
            e.cancelBubble = true;
          };
        }
        // this:当前点击的这个元素curEle  e.target存储的是当前触发的元素curEle
        // 获取自己事件池中绑定的那些方法,并且让这些方法依次的执行
        var ary = e.target["myEvent" + e.type];
        for (var i = 0; i < ary.length; i++) {
          var tempFn = ary[i];
          tempFn.call(this, e);
        }
      }

unbindDOM2():

function off(curEle, eventType, eventFn) {
        var ary = curEle["myEvent" + eventType];
        for (var i = 0; i < ary.length; i++) {
          var cur = ary[i];
          if (cur === eventFn) {
            ary.splice(i, 1);
          }
        }
      }

整个代码

<!--
 * @Author: lemon
 * @Date: 2020-09-17 15:15:13
 * @LastEditTime: 2020-09-17 17:58:04
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \React前端准备\事件\DOM2事件.html
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style type="text/css">
      * {
        margin: 0;
        padding: 0;
      }
      #box {
        margin: 20px auto;
        width: 200px;
        height: 200px;
        background: lightblue;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
    <script type="text/javascript">
      var box = document.getElementById("box");
      function con() {
        console.log(this);
      }
      box.addEventListener("click", con, false);
      box.removeEventListener("click", con, false);
      // 处理DOM2级事件绑定的兼容性问题(绑定方法)
      function bindDOM2(curEle, evenType, eventFn) {
        if ("addEventListener" in document) {
          curEle.addEventListener(evenType, eventFn, false);
          return;
        }
        // eventFn化妆,并且把化妆前的照片贴在自己对应的脑门上
        var tempFn = function () {
          eventFn.call(curEle);
        };
        tempFn.photo = eventFn;
        if (!curEle["myBind" + evenType]) {
          curEle["myBind" + evenType] = [];
        }
        // 解决重复问题:每一次自己在往自定义属性对应的容器中添加前,看一下之前是否已经有了,有的话就不用再重新的添加了,同理也不需要再往事件池中存储了
        var ary = curEle["myBind" + eventType];
        for (var i = 0; i < ary.length; i++) {
          var cur = ary[i];
          if (cur.photo === eventFn) {
            return;
          }
        }
        curEle["myBind" + evenType].push(tempFn);
        curEle.attachEvent("on" + eventType, tempFn);
      }
      function unbindDom2(curEle, eventType, eventFn) {
        if ("removeEventListener" in document) {
          curEle.removeEventListener(eventType, eventFn, false);
          return;
        }
        var ary = curEle["myBind" + evenType];
        for (var i = 0; i < ary.length; i++) {
          if (ary[i].photo === eventFn) {
            ary.splice(i, 1);
            curEle.detachEvent("on" + evenType, ary[i]);
            break;
          }
        }
      }
      // on:创建事件池,并且把需要给当前元素绑定的方法依次的增加到事件池中
      function on(curEle, evenType, eventFn) {
        if (!curEle["myEvent" + evenType]) {
          curEle["myEvent" + evenType] = [];
        }
        var ary = curEle["myEvent" + evenType];
        for (var i = 0; i < ary.length; ++i) {
          var cur = ary[i];
          if (cur === eventFn) {
            return;
          }
        }
        ary.push(eventFn);
        // 执行on的时候, 我们给当前元素绑定了一个点击的行为,当点击得时候执行run方法:
        // run方法中的this是当前元素curEle, 并且浏览器给run传递了一个MouseEvent对象
        bindDOM2(curEle, eventType, run);
      }
      // off:在自己的事件池中把某一个方法移除
      function off(curEle, eventType, eventFn) {
        var ary = curEle["myEvent" + eventType];
        for (var i = 0; i < ary.length; i++) {
          var cur = ary[i];
          if (cur === eventFn) {
            ary.splice(i, 1);
          }
        }
      }
      // run: 我们只给当前元素的带年纪行为绑定一个方法run,当点击事件执行的时候执行的是run方法,我在run方法中根据自己存储的方法顺序分别的再把这些方法执行
      function run(e) {
        e = e || window.event;
        var flag = e.target ? true : false; // IE6~8下不兼容e.target,得到的flag为false
        if (!flag) {
          e.target = e.srcElement;
          e.pageX =
            e.clientX +
            (document.documentElement.scrollLeft || doucment.body.scrollLeft);
          e.pageY =
            e.clientY +
            (document.documentElement.scrollTop || doucment.body.scrollTop);
          e.preventDefault = function () {
            e.returnValue = false;
          };
          e.stopPropagation = function () {
            e.cancelBubble = true;
          };
        }
        // this:当前点击的这个元素curEle  e.target存储的是当前触发的元素curEle
        // 获取自己事件池中绑定的那些方法,并且让这些方法依次的执行
        var ary = e.target["myEvent" + e.type];
        for (var i = 0; i < ary.length; i++) {
          var tempFn = ary[i];
          tempFn.call(this, e);
        }
      }
    </script>
  </body>
</html>
posted @ 2020-09-17 18:01  lemon-Xu  阅读(276)  评论(0编辑  收藏  举报