2012-06-11 12 views
9

Lo que quiero tener es un objeto personalizado que proporcione algunos eventos. Por ejemplo:Implementación de eventos en mi propio objeto

var CustomObjectTextChangedEventName = 'textChanged'; 
var CustomObject = function() { 
    var _this = this; 
    var _text = ""; 

    _this.OnTextChanged = document.createEvent("Event"); 
    _this.OnTextChanged.initEvent(CustomObjectTextChangedEventName, true, false); 

    _this.ChangeText = function (newText) { 
     _text = newText; 
     fireTextChanged(); 
    }; 

    function fireTextChanged() { 
     _this.dispatchEvent(_this.OnTextChanged); 
    } 
} 

El código para utilizar el evento se vería así:

myCustomObject = new CustomObject(); 
myCustomObject.addEventListener(CustomObjectTextChangedEventName, handleTextChanged, false); 

Como se puede ver ... la forma predeterminada de la utilización de eventos en JS. Pero no puedo hacerlo worling ...

Actualmente mi problema es que mi objeto no implementa "addEventListener" y "dispatchEvent". Pero estas funciones se implementan normalmente desde "elemento" ...

¿Puedo hacer que estén disponibles de alguna manera o tengo que implementarlas por mi cuenta? ¿Cómo debo implementarlos? ¿Debo implementar mi propio manejo de eventos? (tener una lista interna de controladores, una función de "agregar" y "quitar", manejar y disparar cada controlador cuando quiero disparar el evento)

¡Saludos!

+0

Me Don; no sé si esto ayuda, pero Backbone.js tiene eventos incorporados. Todos los modelos creados con este pueden desencadenar eventos personalizados usando la sintaxis 'object.trigger (event_name)' – Deeptechtons

+0

. También es fácil con jQuery ... por eso pensé que no podía ser tan difícil: P $ (_ this) .trigger (CustomObjectTextChangedEventName , _text); $ (myCustomObject) .bind (CustomObjectTextChangedEventName, handleTextChanged); –

Respuesta

15

La función addEventListener es un método de la clase Element. Una forma es hacer CustomObject Heredar del Element así:

CustomObject.prototype = Element.prototype; 

El problema es que Element clase puede tener diferentes implementaciones entre los diferentes navegadores. Entonces, por ejemplo, los eventos de disparos pueden no ser fáciles (ver this post).

Así que te aconsejo que hagas esto por ti mismo. No es difícil, intentar algo como esto:

var CustomObject = function() { 
    var _this = this; 
    _this.events = {}; 

    _this.addEventListener = function(name, handler) { 
     if (_this.events.hasOwnProperty(name)) 
      _this.events[name].push(handler); 
     else 
      _this.events[name] = [handler]; 
    }; 

    _this.removeEventListener = function(name, handler) { 
     /* This is a bit tricky, because how would you identify functions? 
      This simple solution should work if you pass THE SAME handler. */ 
     if (!_this.events.hasOwnProperty(name)) 
      return; 

     var index = _this.events[name].indexOf(handler); 
     if (index != -1) 
      _this.events[name].splice(index, 1); 
    }; 

    _this.fireEvent = function(name, args) { 
     if (!_this.events.hasOwnProperty(name)) 
      return; 

     if (!args || !args.length) 
      args = []; 

     var evs = _this.events[name], l = evs.length; 
     for (var i = 0; i < l; i++) { 
      evs[i].apply(null, args); 
     } 
    }; 
} 

Ahora su uso es tan simple como:

var co = new CustomObject(); 
co.addEventListener('textChange', function(name) { 
    console.log(name); 
}); 
co.fireEvent('textChange', ['test']); 

Esta es una solución básica. Es posible que desee modificarlo, pero creo que debe comprender la idea.

+0

Eso es lo que mencioné con "tener una lista interna de controladores, una función de" agregar "y" quitar ", y desencadenar cada controlador cuando quiero activar el evento" =) ¡Gracias! –

+0

@DominikKirschenhofer Cool. Me olvidé del manejador 'remove', así que acabo de agregarlo. Deberia de funcionar. :) – freakish

+1

En cuanto a la parte "complicada", eliminar controladores pasando el mismo objeto de función: lo mismo es cierto para los controladores de eventos nativos. Acabo de probar un evento 'click' de botones, y' removeEventListener' no funcionó a menos que proporcione una referencia al mismo objeto de función. – GolfWolf

1

No estoy seguro sobre todo 100% pero la próxima es el resultado de mi viejo investigación dentro de este problema:

  • No se puede poner a disposición de alguna manera esto.
  • Simplemente puede implementar su propia lógica. Para esto puede usar el código que existe en el artículo MDN element.removeEventListener con pocos cambios. A continuación se copiar \ pasado del código de enlace MDN:

// code source: MDN: https://developer.mozilla.org/en/DOM/element.removeEventListener 
// without changes 
if (!Element.prototype.addEventListener) { 
    var oListeners = {}; 
    function runListeners(oEvent) { 
    if (!oEvent) { oEvent = window.event; } 
    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) { 
     if (oEvtListeners.aEls[iElId] === this) { 
     for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); } 
     break; 
     } 
    } 
    } 
    Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { 
    if (oListeners.hasOwnProperty(sEventType)) { 
     var oEvtListeners = oListeners[sEventType]; 
     for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { 
     if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } 
     } 
     if (nElIdx === -1) { 
     oEvtListeners.aEls.push(this); 
     oEvtListeners.aEvts.push([fListener]); 
     this["on" + sEventType] = runListeners; 
     } else { 
     var aElListeners = oEvtListeners.aEvts[nElIdx]; 
     if (this["on" + sEventType] !== runListeners) { 
      aElListeners.splice(0); 
      this["on" + sEventType] = runListeners; 
     } 
     for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) { 
      if (aElListeners[iLstId] === fListener) { return; } 
     }  
     aElListeners.push(fListener); 
     } 
    } else { 
     oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] }; 
     this["on" + sEventType] = runListeners; 
    } 
    }; 
    Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { 
    if (!oListeners.hasOwnProperty(sEventType)) { return; } 
    var oEvtListeners = oListeners[sEventType]; 
    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { 
     if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } 
    } 
    if (nElIdx === -1) { return; } 
    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) { 
     if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); } 
    } 
    }; 
} 
  • Creo que lo único que tiene que cambiar es reemplazar Element.prototype con CustomObject.prototype. Y para admitir dispathEvent, debe agregar la línea de código CustomObject.prototype.dispatchEvent = runListener;. También puede ser mejor incluir este código en la función de cierre;

No probé esto en mis aplicaciones, pero quizás esto pueda ayudarlo.

ACTUALIZACIÓN: siguientes puntos de enlace en código fuente que contiene XObject() clase que soporta caso la adición/eliminación y el envío de eventos. Ejemplo de prueba incluido Todo el código se basa en la respuesta anterior. http://jsfiddle.net/8jZrR/

+0

@Dominik Kirschenhofer, ver el enlace en ** ACTUALIZACIÓN: ** párrafo –

+0

¡COOL! ¡Gracias! –

1

He mejorado mi muestra con el código de monstruoso. Todavía extraería la parte de manejo de eventos en una "clase base" ... tal vez cuando haya más tiempo =)

¡También hay una muestra para usar jQuery!

<!doctype html> 
<html lang="en"> 
<head>  
    <title>Custom Events Test</title>  
    <meta charset="utf-8">  
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>  
    <script> 
     /* jQuery 

     var CustomObjectTextChangedEventName = 'textChanged'; 
     var CustomObject = function() { 
      var _this = this; 
      var _text = ""; 

      _this.ChangeText = function (newText) { 
       _text = newText; 
       fireTextChanged(); 
      }; 

      function fireTextChanged() { 
       $(_this).trigger(CustomObjectTextChangedEventName, _text); 
      } 
     } 

     var myCustomObject; 
     $(document).ready(function() { 
      myCustomObject = new CustomObject(); 
      $(myCustomObject).bind(CustomObjectTextChangedEventName, handleTextChanged); 
     }) 

     function handleTextChanged(event, msg) { 
      window.alert(msg); 
     } 

     function buttonClick() { 
      var newText = document.getElementById('tbText').value; 

      myCustomObject.ChangeText(newText); 
     } 

     */ 


     var CustomObjectTextChangedEventName = 'textChanged'; 
     var CustomObject = function (alias) { 
      var _this = this; 
      var _events = {}; 
      var _text = ""; 

      _this.Alias = alias; 

      _this.OnTextChanged = document.createEvent("Event"); 
      _this.OnTextChanged.initEvent(CustomObjectTextChangedEventName, true, false); 

      _this.ChangeText = function (newText) { 
       var args = new TextChangedEventArgs(); 
       args.OldText = _text; 
       args.NewText = newText; 

       _text = newText; 
       fireEvent(CustomObjectTextChangedEventName, args); 
      }; 

      _this.addEventListener = function (name, handler) { 
       if (_events.hasOwnProperty(name)) 
        _events[name].push(handler); 
       else 
        _events[name] = [handler]; 
      }; 

      _this.removeEventListener = function (name, handler) { 
       /* This is a bit tricky, because how would you identify functions? 
       This simple solution should work if you pass THE SAME handler. */ 
       if (!_events.hasOwnProperty(name)) 
        return; 

       var index = _events[name].indexOf(handler); 
       if (index != -1) 
        _events[name].splice(index, 1); 
      }; 

      function fireEvent(name, args) { 
       if (!_events.hasOwnProperty(name)) 
        return; 

       var evs = _events[name], l = evs.length; 
       for (var i = 0; i < l; i++) { 
        evs[i](_this, args); 
       } 
      } 
     } 

     var TextChangedEventArgs = function() { 
      var _this = this; 

      _this.OldText = null; 
      _this.NewText = null; 
     } 

     var myCustomObject; 
     var myCustomObject2; 
     window.onload = function() { 
      myCustomObject = new CustomObject("myCustomObject"); 
      myCustomObject.addEventListener(CustomObjectTextChangedEventName, handleTextChanged); 

      myCustomObject2 = new CustomObject("myCustomObject2"); 
      myCustomObject2.addEventListener(CustomObjectTextChangedEventName, handleTextChanged); 
     }; 

     function handleTextChanged(sender, args) { 
      window.alert('At ' + sender.Alias + ' from [' + args.OldText + '] to [' + args.NewText + ']'); 
     } 

     function buttonClick() { 
      var newText = document.getElementById('tbText').value; 

      myCustomObject.ChangeText(newText); 
     } 

     function buttonClick2() { 
      var newText = document.getElementById('tbText2').value; 

      myCustomObject2.ChangeText(newText); 
     } 
    </script> 
</head> 
<body> 
    <input type="text" id="tbText" /> 
    <input type="button" value="Change" onclick="buttonClick();" /> 

    <input type="text" id="tbText2" /> 
    <input type="button" value="Change" onclick="buttonClick2();" /> 
</body> 

Cuestiones relacionadas