用JavaScript编写一个自定义事件调度程序

Write a custom event dispatcher in JavaScript?

本文关键字:一个 自定义 事件 调度程序 JavaScript      更新时间:2023-09-26

如何在JavaScript中向自己类的对象添加事件侦听器并从中调度事件

在ActionScript3中,我可以简单地从Sprite/DisplayObject继承并使用那里可用的方法。像这样:

// ActionScript-3:
// I can add event listeners to all kinds of events
var mySprite: Sprite = new MySprite();
mySprite.addEventListener("my_menu_item_click", onMenuItemClick);
// later I can dispatch an event from one of my objects
mySprite.dispatchEvent(new Event("my_menu_item_click", ...));

我希望在JavaScript中也有同样的功能。到目前为止,我对window.addEventListener(...)document.addEventListener(...)有所了解。到目前为止,我有自己的JavaScript Sprite类,我想用它来调度我自己的事件。

// JavaScipt:
function Sprite()
{
    this.x = 0;
    this.y = 0;
    // ...
}

由于这两种语言似乎都是如此";类似的";我想我需要从某个类继承事件?还是我必须使用一些全局变量,如窗口和/或文档?

我在这里使用HTML5。我只有1个画布和一堆绘制在上面并对用户输入做出反应的精灵。我希望一个精灵A订阅另一个精灵B的事件。但不订阅第三个精灵C的事件。

我尝试将这些方法添加到我的Sprite类中并成功了
当然还没有完成,但至少它起作用了
这就是我想要的。

function Sprite()
{
    // ...
    this.eventListeners = new Array();
    this.addEventListener = function(type, eventHandler)
    {
        var listener = new Object();
        listener.type = type;
        listener.eventHandler = eventHandler;
        this.eventListeners.push(listener);
    }
    this.dispatchEvent = function(event)
    {
        for (var i = 0; i < this.eventListeners.length; i++)
            if (event.type == this.eventListeners[i].type)
                this.eventListeners[i].eventHandler(event);
    }
}

这是一种"函数"方法,我不喜欢在javascript中使用"new"answers"This"。我喜欢普通对象、对等对象或扩展对象。

// Some helper functions, should be imported from a different file
const partial = fn => (...pargs) => (...args) => fn.apply(null, [...pargs, ...args]);
const partialRight = fn => (...pargs) => (...args) => fn.apply(null, [...args, ...pargs.reverse()]);
// Module starts here
const on = (listeners, type, listener, once) => {
  if (!listeners[type]) {
    listeners[type] = [];
  }
  if (listeners[type].indexOf(listener) < 0) {
    listener.once = once;
    listeners[type].push(listener);
  }
};
const once = partialRight(on)(true);
const off = (listeners, type, listener) => {
  const listenerType = listeners[type];
  if (listenerType && listenerType.length) {
    const index = listenerType.indexOf(listener);
    if (index !== -1) {
      listenerType.splice(index, 1);
    }
  }
  if ((listenerType && !listenerType.length) || !listener) {
    delete listeners[type];
  }
};
const emit = (listeners, type, ...data) => {
  if (listeners[type]) {
    listeners[type].forEach(listener => {
      listener.apply(null, data);
      if (listener.once) {
        off(listeners, type, listener);
      }
    });
  }
};
// you could use "export default () => {}" to make it an importable module
const eventEmitter = () => {
  const listeners = {};
  return {
    on: partial(on)(listeners),
    once: partial(once)(listeners),
    off: partial(off)(listeners),
    emit: partial(emit)(listeners),
  };
};
const myObj = Object.create(Object.assign({}, eventEmitter()));
myObj.on('hello', name => console.log(name));
setTimeout(() => {
  myObj.emit('hello', 'Csaba')
}, 2000)

您可以在JS中使用Event和CustomEvent对象执行几乎相同的操作:

var event = new Event('build');
// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);
// Dispatch the event.
elem.dispatchEvent(event);

来源:MDN(https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events)

您可以自己制作,这个是通用的,非常简单。实际上我自己也用:D

这就是您将获得的功能。

  • addEventListener()
  • removeEventlistener()
  • dispatchEvent()(或者你想怎么称呼它)

这个函数将向对象添加所需的方法,同时返回一个可以调度事件的函数。

// Snippet  =========================================
function createEventDispatcher(o) {
  var L = o.__listeners = {};
  o.addEventListener = function(n, fn) { L[n] = L[n] || []; L[n].push(fn); };
  o.removeEventListener = function(n, fn) { var a = L[n]; for (var i = 0; i < a.length; i++) if (a[i] === fn) a.splice(i, 1);};
  return function() { var a = Array.prototype.slice.call(arguments); var l = L[a.shift()]; if (l)  for (var i = 0; i < l.length; i++) l[i].apply(l[i], a)};
}

// Simplified example of usage =========================================
function App(){
    // Add functionality
    var dispatchEvent = createEventDispatcher(this); // Call snippet
    // Use functionality
    var count = 0;
    setInterval(function(){ 
        dispatchEvent("something",{msg:"hello",count:count++});
    },100);
}();
// Somewhere outside your App    
    function onSomething(event){
        console.log(event.msg + "["+event.count+"]");
        if(event.count >= 10){ 
            // Remove eventlistener 
            myApp.removeEventListener("something",onSomething);
        } 
   }
    var myApp = new App();    
    myApp.addEventListener("something",onSomething);
// Easy

https://jsfiddle.net/squadjot/0n2nby7k/

如果您想从对象中删除所有侦听器,只需执行以下操作即可。

myApp.__listeners = {};