如何使用javascript实现完整的事件系统?

时间:2014-06-21 14:54:39

标签: javascript events javascript-events event-handling

我正在创建一个客户端动态博客引擎。 现在我需要一个事件系统来处理来自DOM元素和引擎的许多操作。 比如引擎正在加载文章,用户正在切换主题......

我不想使用库来执行此操作。

到目前为止,我所做的是使用列表来存储事件的回调

但我希望每个回调都适用于不同的对象。就像DOM事件一样。

我可以为每个对象添加一个类似id的属性,并在事件中存储(id,回调)。我觉得它不太好。当动态生成的对象出现时,它可能很复杂。

如何实现它像DOM事件一样简单(使用)?

4 个答案:

答案 0 :(得分:1)

Recently,我想向vanilla JavaScript对象添加简单的事件监听器。这是我提出的解决方案

(这需要ecmascript >= 5

function Emitter () {
  var eventTarget = document.createDocumentFragment();

  function delegate (method) {
    this[method] = eventTarget[method].bind(eventTarget);
  }

  Emitter.methods.forEach(delegate, this);
}

Emitter.methods = ["addEventListener", "dispatchEvent", "removeEventListener"];

现在是"班级"使用它

function Example () {
  Emitter.call(this);
}

让我们现在试试吧!

var e = new Example();

e.addEventListener("something", function(event) {
  alert("something happened! check the console too!");
  console.log(event);
});

e.dispatchEvent(new Event("something"));
祝你好运!

答案 1 :(得分:0)

您可以实现中介模式:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/#mediatorpatternjavascript

在本书中,您需要了解它。

答案 2 :(得分:0)

class SimpleEvent {
  constructor() {
    this.onEvent = {}
    this.handler = function(funct, name) {
      var owner = this
      var name = name
      this.onEvent[name] = funct
      var remove = function() {
        delete this.owner.onEvent[this.name]
        delete this.owner
        delete this.name
        delete this.remove
      }
      if ((((!(remove == undefined && name == undefined)) && (remove == undefined || name == undefined)))) {
        throw new Error("-_-")
      } else {
        return (remove == undefined || name == undefined) ? (undefined) : ({
          remove: remove,
          name: name
        })
      }
    }
  }
  Fire() {
    for (var i in this.onEvent) {
      this.onEvent[i](arguments)
    }
  }
}

答案 3 :(得分:0)

ok 最近正在研究这个解决方案 https://github.com/browserify/events#readme 只是为了它在我的个人环境中保持一致,但我也想粘贴我在 slick grid 项目中找到的一个基本的,这对以下内容非常有用只有 150 行代码,我认为对事件有一个很好的基本了解

/***
 * An event object for passing data to event handlers and letting them control propagation.
 * <p>This is pretty much identical to how W3C and jQuery implement events.</p>
 * @class EventData
 * @constructor
 */
function EventData() {
  var isPropagationStopped = false;
  var isImmediatePropagationStopped = false;

  /***
   * Stops event from propagating up the DOM tree.
   * @method stopPropagation
   */
  this.stopPropagation = function() {
    isPropagationStopped = true;
  };

  /***
   * Returns whether stopPropagation was called on this event object.
   * @method isPropagationStopped
   * @return {Boolean}
   */
  this.isPropagationStopped = function() {
    return isPropagationStopped;
  };

  /***
   * Prevents the rest of the handlers from being executed.
   * @method stopImmediatePropagation
   */
  this.stopImmediatePropagation = function() {
    isImmediatePropagationStopped = true;
  };

  /***
   * Returns whether stopImmediatePropagation was called on this event object.\
   * @method isImmediatePropagationStopped
   * @return {Boolean}
   */
  this.isImmediatePropagationStopped = function() {
    return isImmediatePropagationStopped;
  };
}

/***
 * A simple publisher-subscriber implementation.
 * @class Event
 * @constructor
 */
function Event() {
  var handlers = [];

  /***
   * Adds an event handler to be called when the event is fired.
   * <p>Event handler will receive two arguments - an <code>EventData</code> and the <code>data</code>
   * object the event was fired with.<p>
   * @method subscribe
   * @param fn {Function} Event handler.
   */
  this.subscribe = function(fn) {
    handlers.push(fn);
  };

  /***
   * Removes an event handler added with <code>subscribe(fn)</code>.
   * @method unsubscribe
   * @param fn {Function} Event handler to be removed.
   */
  this.unsubscribe = function(fn) {
    for (var i = handlers.length - 1; i >= 0; i--) {
      if (handlers[i] === fn) {
        handlers.splice(i, 1);
      }
    }
  };

  /***
   * Fires an event notifying all subscribers.
   * @method notify
   * @param args {Object} Additional data object to be passed to all handlers.
   * @param e {EventData}
   *      Optional.
   *      An <code>EventData</code> object to be passed to all handlers.
   *      For DOM events, an existing W3C/jQuery event object can be passed in.
   * @param scope {Object}
   *      Optional.
   *      The scope ("this") within which the handler will be executed.
   *      If not specified, the scope will be set to the <code>Event</code> instance.
   */
  this.notify = function(args, e, scope) {
    e = e || new EventData();
    scope = scope || this;

    var returnValue;
    for (var i = 0; i < handlers.length && !(e.isPropagationStopped() || e.isImmediatePropagationStopped()); i++) {
      returnValue = handlers[i].call(scope, e, args);
    }

    return returnValue;
  };
}

function EventHandler() {
  var handlers = [];

  this.subscribe = function(event, handler) {
    handlers.push({
      event: event,
      handler: handler
    });
    event.subscribe(handler);

    return this; // allow chaining
  };

  this.unsubscribe = function(event, handler) {
    var i = handlers.length;
    while (i--) {
      if (handlers[i].event === event &&
        handlers[i].handler === handler) {
        handlers.splice(i, 1);
        event.unsubscribe(handler);
        return;
      }
    }

    return this; // allow chaining
  };

  this.unsubscribeAll = function() {
    var i = handlers.length;
    while (i--) {
      handlers[i].event.unsubscribe(handlers[i].handler);
    }
    handlers = [];

    return this; // allow chaining
  };
}

console.log("Start Demo")

car1 = {}
car1.onhonk = new Event();
car1.honk = ()=>{
  console.log('car1 Honked');
  car1.onhonk.notify({noise:'meep meep'}) 
};


car2 = {}
car2.honkListener = (e, args) => {
  console.log("car2 heard: ", args.noise);
}

car1.honk();//not heard yet 

car1.onhonk.subscribe(car2.honkListener);
car1.honk();