web-dev-qa-db-ja.com

JavaScriptでDOMイベントを使用しないカスタムイベントモデル

私はJavaScriptとプログラミング一般に不慣れで、オブジェクトとイベントについていくつか質問があります。

オブジェクトがあるとしましょう:

var computer = {
    keyboard: {}
}

私が探しているのは、イベントをキーボードオブジェクトに登録する方法です。

computer.keyboard.registerEvent( "keyEscape" );

イベントを起動します。

computer.keyboard.dispatchEvent( "keyEscape" );

そして、イベントハンドラーを作成します。

computer.keyboard.addEventListener( "keyEscape", function() {...} );

オブジェクトではなくDOM要素でこれを行う方法を知っています。これはJavaScriptで実行できるものですか(おそらくJQueryの助けを借りて)?

ほんの少しのガイダンスでも大歓迎です。

45
NTDave

DOMイベントに依存せずに完全にスタンドアロンのイベントシステムを作成する場合は、reactorパターンを使用してこのようなものを作成できます

function Event(name){
  this.name = name;
  this.callbacks = [];
}
Event.prototype.registerCallback = function(callback){
  this.callbacks.Push(callback);
}

function Reactor(){
  this.events = {};
}

Reactor.prototype.registerEvent = function(eventName){
  var event = new Event(eventName);
  this.events[eventName] = event;
};

Reactor.prototype.dispatchEvent = function(eventName, eventArgs){
  this.events[eventName].callbacks.forEach(function(callback){
    callback(eventArgs);
  });
};

Reactor.prototype.addEventListener = function(eventName, callback){
  this.events[eventName].registerCallback(callback);
};

DOMイベントモデルのように使用します

var reactor = new Reactor();

reactor.registerEvent('big bang');

reactor.addEventListener('big bang', function(){
  console.log('This is big bang listener yo!');
});

reactor.addEventListener('big bang', function(){
  console.log('This is another big bang listener yo!');
});

reactor.dispatchEvent('big bang');

Live at JSBin

52
Mohsen

独自のイベント処理メカニズムを実装したくない場合は、私のアプローチが好きかもしれません。通常のDOMイベント(preventDefault()など)から知っているすべての機能を取得できます。ブラウザーの実装済みのDOMイベント処理機能を使用しているため、軽量であると思います。

オブジェクトのコンストラクターで通常のDOM EventTargetオブジェクトを作成し、すべてのEventTargetインターフェイス呼び出しをDOM EventTargetオブジェクトに渡します。

var MyEventTarget = function(options) {
    // Create a DOM EventTarget object
    var target = document.createTextNode(null);

    // Pass EventTarget interface calls to DOM EventTarget object
    this.addEventListener = target.addEventListener.bind(target);
    this.removeEventListener = target.removeEventListener.bind(target);
    this.dispatchEvent = target.dispatchEvent.bind(target);

    // Room your your constructor code 
}

// Create an instance of your event target
myTarget = new MyEventTarget();
// Add an event listener to your event target
myTarget.addEventListener("myevent", function(){alert("hello")});
// Dispatch an event from your event target
var evt = new Event('myevent');
myTarget.dispatchEvent(evt);

お使いのブラウザでテストするための JSFiddleスニペット もあります。

38
Torben

ここで少しネクロポストしますが、私は昨晩このようなものを書いただけです-超シンプルで、Backbone.jsイベントモジュールに基づいています:

EventDispatcher = {

    events: {},

    on: function(event, callback) {
        var handlers = this.events[event] || [];
        handlers.Push(callback);
        this.events[event] = handlers;
    },

    trigger: function(event, data) {
        var handlers = this.events[event];

        if (!handlers || handlers.length < 1)
            return;

        [].forEach.call(handlers, function(handler){
            handler(data);
        });
    }
};

このアプローチは非常にシンプルで拡張性があり、必要に応じて、その上にさらに洗練されたイベントシステムを構築できます。

EventDispatcherの使用は次のように簡単です:

function initializeListeners() {
    EventDispatcher.on('fire', fire); // fire.bind(this) -- if necessary
}

function fire(x) {
    console.log(x);
}

function thingHappened(thing) {
    EventDispatcher.trigger('fire', thing);
}

いくつかの単純な名前空間を使用すると、モジュール間で基本的なイベントを簡単に渡すことができます。

12
Jordan Foreman

JQueryを使用してそれを行うことができます。

カスタムイベントをサブスクライブするには:

$(computer.keyboard).on('keyEscape', function(e){
    //Handler code
});

カスタムイベントをスローする場合:

$(computer.keyboard).trigger('keyEscape', {keyCode:'Blah blah'});

これを行うための最も良い方法ではないかもしれませんが、JQueryロジックをラップするメソッド(addEventListener、dispatchEventなど)で関数を作成して、ネイティブに見えるAPIとJQueryの両方をサポートすることもできます。

4
Philipp Munin

おそらく、いくつかのオブジェクト間の通信手段としてイベントメカニズムが必要です。

あなたがそれを達成する方法は次のとおりです。

/**
 * EventfulObject constructor/base.
 * @type EventfulObject_L7.EventfulObjectConstructor|Function
 */
var EventfulObject = function() {
  /**
   * Map from event name to a list of subscribers.
   * @type Object
   */
  var event = {};
  /**
   * List of all instances of the EventfulObject type.
   * @type Array
   */
  var instances = [];
  /**
   * @returns {EventfulObject_L1.EventfulObjectConstructor} An `EventfulObject`.
   */
  var EventfulObjectConstructor = function() {
    instances.Push(this);
  };
  EventfulObjectConstructor.prototype = {
    /**
     * Broadcasts an event of the given name.
     * All instances that wish to receive a broadcast must implement the `receiveBroadcast` method, the event that is being broadcast will be passed to the implementation.
     * @param {String} name Event name.
     * @returns {undefined}
     */
    broadcast: function(name) {
      instances.forEach(function(instance) {
        (instance.hasOwnProperty("receiveBroadcast") && typeof instance["receiveBroadcast"] === "function") &&
        instance["receiveBroadcast"](name);
      });
    },
    /**
     * Emits an event of the given name only to instances that are subscribed to it.
     * @param {String} name Event name.
     * @returns {undefined}
     */
    emit: function(name) {
      event.hasOwnProperty(name) && event[name].forEach(function(subscription) {
        subscription.process.call(subscription.context);
      });
    },
    /**
     * Registers the given action as a listener to the named event.
     * This method will first create an event identified by the given name if one does not exist already.
     * @param {String} name Event name.
     * @param {Function} action Listener.
     * @returns {Function} A deregistration function for this listener.
     */
    on: function(name, action) {
      event.hasOwnProperty(name) || (event[name] = []);
      event[name].Push({
        context: this,
        process: action
      });

      var subscriptionIndex = event[name].length - 1;

      return function() {
        event[name].splice(subscriptionIndex, 1);
      };
    }
  };

  return EventfulObjectConstructor;
}();

var Model = function(id) {
  EventfulObject.call(this);
  this.id = id;
  this.receiveBroadcast = function(name) {
    console.log("I smell another " + name + "; and I'm model " + this.id);
  };
};
Model.prototype = Object.create(EventfulObject.prototype);
Model.prototype.constructor = Model;

// ---------- TEST AND USAGE (hopefully it's clear enough...)
// ---------- note: I'm not testing event deregistration.

var ob1 = new EventfulObject();
ob1.on("crap", function() {
  console.log("Speaking about craps on a broadcast? - Count me out!");
});

var model1 = new Model(1);

var model2 = new Model(2);
model2.on("bust", function() {
  console.log("I'm model2 and I'm busting!");
});

var ob2 = new EventfulObject();
ob2.on("bust", function() {
  console.log("I'm ob2 - busted!!!");
});
ob2.receiveBroadcast = function() {
  console.log("If it zips, I'll catch it. - That's me ob2.");
};

console.log("start:BROADCAST\n---------------");
model1.broadcast("crap");
console.log("end  :BROADCAST\n---------------\n-\n-\n");
console.log("start:EMIT\n---------------");
ob1.emit("bust");
console.log("end:EMIT\n---------------");
<h1>...THE SHOW IS ON YOUR CONSOLE!</h1>
0
Igwe Kalu