是否可以扩展EventTarget接口?

时间:2013-10-27 09:30:10

标签: javascript javascript-events addeventlistener

如果可能的话,我正在寻找答案,甚至是个好主意。

通常,作为IE8及早期版本的修复,使用类似于此的解决方法:

var addEvent = function(obj, e, cb) {
    if(obj.attachEvent) {
        return obj.attachEvent('on' + e, cb);
    } else {
        obj.addEventListener(e, cb, false);
        return true;
    }
}

然后程序员总是使用addEvent而不是addEventListener

是否有任何方法或点可以创建一个addEventListener函数,当attachEvent未定义时它会回绕它?

我认为它有点棘手,因为EventTarget可以是DOM元素,文档或窗口,或者其他一些东西。

2 个答案:

答案 0 :(得分:1)

这取决于你想要走多远。在IE8上,您可以扩展Element.prototype以向所有HTML元素添加功能,这至少是工作的90%。我很确定你不能在IE6中做到这一点(PrototypeJS不得不求助于扩展单个Element实例),我不记得IE7。除非你的目标是东亚市场,否则你基本上可以忽略IE7和更早版本。

以下是您如何执行此操作的示例:

(function() {
  // Functions for IE
  function stopPropagation() {
    this.cancelBubble = true;
  }
  function preventDefault() {
    this.returnValue = false;
  }
  function addEventUsingAttach(eventName, handler)
  {
    this.attachEvent("on" + eventName, function() {
      var e = window.event;
      e.stopPropagation = stopPropagation;
      e.preventDefault = preventDefault;
      handler.call(this, e);
    });
  }

  // Function to add `addEvent` to the given target object
  function extendIt(target)
  {
    if (target.addEventListener) {
      target.addEvent = Element.prototype.addEventListener;
    }
    else {
      target.addEvent = addEventUsingAttach;
    }
  }

  // Add it to `Element.prototype` if we have it
  if (typeof Element !== "undefined" &&
      typeof Element.prototype !== "undefined") {
    extendIt(Element.prototype);
  }

  // Add it to `window` and `document` (etc.)
  extendIt(window);
  extendIt(document);
})();

Live Example | Source

然后您手动扩展其他EventTargets,例如windowdocument(请参阅上面代码清单的末尾)。


原始回答:我最初误解了你的问题是关于添加addEventListener,特别是在IE8上,而实际上你的问题很明显关于添加,但添加自己的addEvent。我将这个答案留给其他读者:

这取决于你想要走多远。在IE8上,您可以扩展Element.prototype以向其添加addEventListener,这将由页面上的所有HTML元素使用(请参见下文)。你添加的垫片不能支持捕获阶段,因为IE在它们原生支持addEventListener之前不支持它。我很确定你不能在早期版本(IE7,IE6)上扩展Element.prototype,PrototypeJS必须回退到扩展旧版本IE的特定元素。但它适用于IE8。

扩展Element.prototype后,您必须手动扩展您提到的其他事件目标,但扩展Element.prototype可以完成大部分工作。

但是如果你这样做并且包含第三方脚本,请注意他们可能会假设addEventListeneer的正确实现完成了捕获阶段。

这是将addEventListener添加到IE8的基本填充程序:

(function() {
  function stopPropagation() {
    this.cancelBubble = true;
  }
  function preventDefault() {
    this.returnValue = false;
  }
  if (typeof Element !== "undefined" &&
      typeof Element.prototype !== "undefined" &&
      !Element.prototype.addEventListener) {
    Element.prototype.addEventListener = function(eventName, handler, useCapture) {
      if (useCapture) {
        throw "Browser doesn't support capturing phase";
      }
      this.attachEvent("on" + eventName, function() {
        var e = window.event;
        e.stopPropagation = stopPropagation;
        e.preventDefault = preventDefault;
        handler.call(this, e);
      });
    };
  }
})();

Live Example | Source

答案 1 :(得分:0)

通常,可以通过将函数附加到对象

来将函数添加到对象
obj.addEventListener = function(/* args*/) { /* body */ }

或将函数附加到对象构造函数的原型

EventTarget.prototype.addEventListener = function(/* args*/) { /* body */ }

使用前者,可以仅在特定对象上调用添加的函数,而后者允许您在从该特定对象构造器创建或将要创建的所有对象上调用该函数。

然而,

  • EventTargets是宿主对象,因此无论是否可以将函数添加到此类对象,它都依赖于实现。
  • EventTargets是主机对象,因此它是依赖于实现的,无论EventTarget.prototype是否实际存在且与本机对象具有相同的含义。
  • 如果某个对象符合EventTarget界面,则很可能已经具有addEventListener功能。
  • attachEvent附加的事件监听器与addEventListener附加的参数不同。

最后,尝试使用蹩脚的DOM支持使用JavaScript支持更多标准的浏览器是不可行的。