从中继承的标准浏览器EventDispatcher类

时间:2018-07-15 21:36:08

标签: javascript

我经常从头开始在JS中实现自己的EventDispatcher类。我猜想在浏览器中的某个位置上可以实现DOM元素的实现,但是EventDispatchers甚至对于与DOM完全无关的其他事情也很有用。浏览器中是否可以继承任何标准类?我需要可以调用addEventListener("event", listener)removeEventListener("event", listener)dispatchEvent("event")的东西,并且需要它来支持同一事件的多个侦听器。节点中有EventEmitter,但是我对它并不十分熟悉,也不知道它是否可以在浏览器中使用。我是否应该使用它,并可能使用browserify之类的东西来翻译整个东西?

3 个答案:

答案 0 :(得分:1)

已经定义了一个接口,可以为您提供所有三种方法,EventTarget

  

Spec

interface EventTarget {
  void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);
  void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
  boolean dispatchEvent(Event event);
};

因此您要做的就是从该接口继承

class MyObject extends EventTarget {
  myCallback(){
    console.log('event triggered');
  }
  myCallback2(){
    console.log('event2 triggered');
  }
}

var obj = new MyObject;
obj.addEventListener('test',obj.myCallback);
obj.addEventListener('test',obj.myCallback2);
obj.dispatchEvent(new Event('test'))

答案 1 :(得分:0)

您没有可以扩展的“ no DOM”类,但是RxJS主题可以满足您的需求。

RxJS

您可以

  • 根据需要订阅任意数量的听众
  • 调用next()来“触发”事件

示例:

// Basic example
const emitter = new Subject();
emitter.subscribe(event => console.log(event));
emitter.next({ type: 'my-custom-event', … });


// class example
class MyClass {
  change = new Subject();
  myFn() {
    this.change.next();
  }
}

const bar = new MyClass();
bar.change.subscribe(e => console.log('change triggered'));

// test
bar.myFn();
=> logs 'change triggered'

您会发现很多有关angular / typescript的文档,但是rxjs并不依赖于angular。

请参阅:https://rxjs-dev.firebaseapp.com/

EventTarget

只要您在浏览器中,都有EventTarget接口。在大多数浏览器中(因为没有编写Edge,没有IE时),它提供了一个构造函数,您可以对其进行扩展(ECMA 2015)。

class MyClass extends EventTarget {
  myFn() {
    this.dispatchEvent(new Event('change'));
  }
}

const bar = new MyClass();
bar.addEventListener('change', e => console.log('change triggered'));

// just for testing
bar.myFn();
=> logs 'change triggered'

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget

答案 2 :(得分:0)

事件分派/侦听是DOM API的一部分,而不是Javascript本身。没有DOM节点,就无法使用此机制。有成千上万个好的,简单的库或更高级的库,并且实现自己很简单(参见microjs上“事件”库的结果量:http://microjs.com/#event)。

您最初的问题是如何使用内置的DOM API事件,因此在下面找到一个仅使用标准DOM API的简单(有点天真)的实现:

// CustomEvent polyfill for IE9-11 from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
(function () {
  if ( typeof window.CustomEvent === "function" ) return false;
  function CustomEvent ( event, params ) {
    params = params || { bubbles: false, cancelable: false, detail: undefined };
    var evt = document.createEvent( 'CustomEvent' );
    evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
    return evt;
   }
  CustomEvent.prototype = window.Event.prototype;
  window.CustomEvent = CustomEvent;
})();

var events = (function() {
  var eventRoot = document.createElement('div');
  function event(strOrObj, data) {
    return typeof strOrObj === 'string' ? new CustomEvent(strOrObj, data ? {detail: data} : undefined) : strOrObj
  };
  return {
    dispatch: function(evt, data) {
      eventRoot.dispatchEvent(event(evt, data));
    },
    addListener: function(evt, listener1, listener2, etc) {
      var listeners = Array.prototype.slice.call(arguments, 1);
      listeners.forEach(function(fn) {
        eventRoot.addEventListener(evt, fn);
      });
    },
    removeListener: function(evt, listener1, listener2, etc) {
      var listeners = Array.prototype.slice.call(arguments, 1);
      listeners.forEach(function(fn) {
        eventRoot.removeEventListener(evt, listener);
      });
    }
  };
}());

events.addListener('click', 
  function(e) { console.log(e.detail.data); },
  function(e) { console.log(e.type); }
)
events.dispatch('click', {data: 'test'})

对于IE9-11的CustomEvent,您需要一个polyfill(包括在上面)。此解决方案适用于大多数情况,但是开发人员倾向于偏向于非DOMElement事件分发/侦听的发布-订阅模式。您可以在http://microjs.com/#pubsub上找到许多易于使用的库。不要被这些库中的“库”有多“老”所迷惑,它们简单而完整,并且大多数都像魅力一样发挥作用。