Я часто реализую свой собственный класс EventDispatcher в JS с нуля. Я предполагаю, что есть некоторая реализация его где-то в браузерах для элементов DOM, но EventDispatchers полезны даже для других вещей, не связанных вообще с DOM. Есть ли какой-либо стандартный класс в браузерах, который я могу унаследовать? Мне нужно что-то, где я могу вызвать addEventListener("event", listener)
, removeEventListener("event", listener)
и dispatchEvent("event")
и мне нужно, чтобы он поддерживал несколько прослушивателей для одного и того же события. Есть EventEmitter из узла, но я не очень хорошо знаком с ним, и я не знаю, будет ли он работать в браузере. Должен ли я использовать его и, возможно, перекрыть всю вещь с помощью чего-то вроде браузера?
Существует уже определенный интерфейс, который дает вам все 3 метода, EventTarget
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'))
Передача/прослушивание событий является частью 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'})
Для CustomEvent для IE9-11 вам понадобится полиполк (см. Выше). Это решение будет работать в большинстве случаев, но разработчики предпочитают шаблоны публикации-подписки для диспетчеризации/прослушивания не-DOMElement. Вы найдете много простых в использовании библиотек на http://microjs.com/#pubsub. Не обманывайтесь, как "старые" некоторые из этих библиотек, они просты и полны, и большинство работает как шарм.
EventTarget
Нет класса "без DOM", который вы могли бы расширить, но субъекты RxJS могут соответствовать вашим потребностям.
RxJS
Вы можете
Пример:
// 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'
Вы найдете много документации вокруг углового/машинописного текста, но rxjs не зависит от углового.
См. 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