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

时间:2015-06-29 08:07:38

标签: javascript events javascript-events

如何在JavaScript中向我自己的类的对象添加事件侦听器和调度事件?
在ActionScript 3中,我可以简单地从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。

4 个答案:

答案 0 :(得分:5)

我尝试将方法添加到我的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);
    }
}

答案 1 :(得分:1)

你可以制作自己的,这个是通用的,非常简单。我实际上自己使用它: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 = {};

答案 2 :(得分:0)

您可以在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

答案 3 :(得分:0)

这是某种“功能”方法,我不喜欢在javascript中使用“new”和“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)