2011-11-11 11 views
13

Estoy implementando el patrón del módulo, y me gustaría saber la mejor/preferida forma de definir y registrar escuchas/manejadores de eventos. La siguiente obra, pero tal vez hay una manera mejor/más simple ...Módulo Javascript Eventos y Escuchas

var MODULE = function() { 

    // private 
    var _field1; 
    var _field2; 

    function localFunc(p) { 
     alert('localFunc'); 
    } 

    // public 
    return { 
     // properties 
     prop1: _field1, 

     // events 
     myEvent1Handler: {}, 
     myEvent1: function() {myEvent1Handler();}, 
     myEvent2Handler: {}, 
     myEvent2: function() {myEvent2Handler();}, 

     addListener: function (event,func) { 
      if (event == "myEvent1") 
       myEvent1Handler = func; 

      if (event == "myEvent2") 
       myEvent2Handler = func;  
     }, 

     // public methods 
     method1: function (p) { 
      alert('method1 says:' + p); 
      MODULE.myEvent1(); 
     }, 
     method2: function (p) { 
      alert('method2 doing stuff'); 
      localFunc(p); 
      MODULE.myEvent2(); 
     } 

    }; 
}(); 

// register for events 
MODULE.addListener("myEvent1",function(){alert('fired1');}); 
MODULE.addListener("myEvent2",function(){alert('fired2');}); 

// use module (only event1 should fire!) 
MODULE.method1("hello"); 

Pruébelo:

http://jsfiddle.net/RqusH/3/

Parece que una gran cantidad de trabajo para tener myEventx, myEventHandlerx y addListener ?

+1

Cuando se llama 'addListener()', no es que la creación de '' myEvent1Handler' o myEvent2Handler' como _GLOBAL_ las variables que hacen referencia al parámetro 'func' aprobada en? No establecerá las propiedades del mismo nombre ya definidas en su objeto a menos que diga 'this.myEvent1Handler = ...' - y luego 'this.myEvent1Handler()' en su función 'myEvent1'. (O 'MODULE.myEvent1Handler' como que tiene' MODULE.myEvent1() 'en' method1'.) – nnnnnn

+0

¿Qué problema está tratando de resolver en realidad? Esto parece una gran sobrecarga que en realidad no hace más que construir un andamio. Tal vez si supiéramos lo que en realidad está tratando de lograr, podríamos ayudarlo a encontrar la mejor manera de hacerlo. – jfriend00

+0

Gracias ... Quiero eventos en MODULE, para que un usuario de MODULE pueda engancharse en eventos. Los métodos de MODULE tendrán solicitudes asincrónicas (usando jquery) así que quiero usar eventos para indicar cuándo se ha completado una solicitud asincrónica. – ZimSystem

Respuesta

9

Normalmente, no respondería a una pregunta de arquitectura con una implementación específica (especialmente una que depende de una biblioteca de terceros como jQuery), pero dado que mi implementación promueve la reutilización y estamos hablando de patrones, la presentaré un pequeño plugin jQuery, $ .eventable, que aumenta los objetos de JavaScript con los métodos de evento de jQuery.

Este complemento le permitirá implementar la capacidad de manejo de eventos en cualquier objeto (o instancia de clase) con una simple llamada.

jQuery.eventable = function (obj) { 
    // Allow use of Function.prototype for shorthanding the augmentation of classes 
    obj = jQuery.isFunction(obj) ? obj.prototype : obj; 
    // Augment the object (or prototype) with eventable methods 
    return $.extend(obj, jQuery.eventable.prototype); 
}; 

jQuery.eventable.prototype = { 

    // The trigger event must be augmented separately because it requires a 
    // new Event to prevent unexpected triggering of a method (and possibly 
    // infinite recursion) when the event type matches the method name 
    trigger: function (type, data) { 
    var event = new jQuery.Event(type); 
    event.preventDefault();     
    jQuery.event.trigger(event, data, this); 
    return this; 
    } 
}; 

// Augment the object with jQuery's event methods 
jQuery.each(['bind', 'one', 'unbind', 'on', 'off'], function (i, method) { 
    jQuery.eventable.prototype[method] = function (type, data, fn) { 
    jQuery(this)[method](type, data, fn); 
    return this; 
    }; 
}); 

Si se incluye que el fragmento, se puede implementar la solución de la siguiente manera:

var MODULE = function() { 

    // private 
    var _field1; 
    var _field2; 

    function localFunc(p) { 
    alert('localFunc'); 
    } 

    // public 
    return $.eventable({ 

    // properties 
    prop1: _field1, 

    // public methods 
    method1: function(p) { 
     alert('method1 says:' + p); 
     this.trigger('myEvent1'); 
    }, 

    method2: function(p) { 
     alert('method2 doing stuff'); 
     localFunc(p); 
     this.trigger('myEvent2'); 
    } 

    }); 
}(); 

// register for events 
MODULE.on("myEvent1", function() { 
    alert('fired1'); 
}); 
MODULE.on("myEvent2", function() { 
    alert('fired2'); 
}); 

// use module (only event1 should fire!) 
MODULE.method1("hello"); 

su módulo tiene ahora los siguientes métodos: se puede llamar

MODULE.on(event, /* data, */ handler); 
MODULE.bind(event, /* data, */ handler); 
MODULE.one(event, /* data ,*/ handler); 
MODULE.off(event, handler); 
MODULE.unbind(event, handler); 
MODULE.trigger(event /*, data */); 

donde evento es un espacio- lista delimitada de eventos, manejador es su devolución de llamada, y los datos son un valor opcional para pasar a sus devoluciones de llamada.

Puede consultar jQuery's documentation para obtener más información.

+0

Esto es sobresaliente y coincide con el patrón que suelo usar a la perfección. ¡Gracias! Voy a trabajar en esto muy cuidadosamente ... – Ricky

2

El patrón revelador del módulo hace que regrese un objeto anónimo. Si en su lugar lo declaras como una variable y lo devuelves, significa que puedes usar los métodos estándar de jQuery event con bastante facilidad, tanto dentro del módulo para generar eventos como externamente para responder a ellos. Tenga en cuenta que debe convertirlo en un objeto jQuery de antemano.

var controller = (function() 
{ 
    function doAThing() 
    { 
    // Things getting done here 
    $(interface).trigger("complete"); 
    } 

    var interface = { 
    doAThing: doAThing 
    }; 
    return interface; 
})(); 

$(controller).on("complete", function() { console.log("Thing Done"); }); 
controller.doAThing(); 
Cuestiones relacionadas