2012-06-11 16 views
9

Quello che voglio è un oggetto personalizzato che fornisce alcuni eventi. Per esempio:Implementazione di eventi nel mio oggetto

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); 
    } 
} 

Il codice per utilizzare l'evento sarà simile:

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

Come si può vedere ... il modo di default di utilizzare gli eventi in JS. Ma non posso renderlo preoccupante ...

Attualmente il mio problema è che il mio oggetto non implementa "addEventListener" e "dispatchEvent". Ma queste funzioni sono normalmente implementate da "elemento" ...

Posso renderle disponibili in qualche modo o devo implementarle per conto mio? Come devo implementarli? Devo implementare il mio eventhandling? (avendo un elenco interno di gestori, una funzione "aggiungi" e "rimuovi" -handler e licenzia ogni gestore quando voglio attivare l'evento)

Saluti!

+0

I don; so se questo aiuta, ma Backbone.js ha eventi costruite al loro interno. Ogni modello creato utilizzandolo può attivare eventi personalizzati usando la sintassi 'object.trigger (event_name)' – Deeptechtons

+0

È anche facile con jQuery ... ecco perché ho pensato che non fosse così difficile: P $ (_ this) .trigger (CustomObjectTextChangedEventName , _testo); $ (myCustomObject) .bind (CustomObjectTextChangedEventName, handleTextChanged); –

risposta

15

La funzione addEventListener è un metodo della classe Element. Un modo è quello di rendere CustomObject erediti da Element come questo:

CustomObject.prototype = Element.prototype; 

Il problema è che Element classe può avere diverse implementazioni tra diversi browser. Quindi, ad esempio, gli eventi di accensione potrebbero non essere facili (vedere this post).

Quindi consiglio di farlo da solo. Non è difficile, provare qualcosa di simile:

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); 
     } 
    }; 
} 

Ora il suo utilizzo è semplice come:

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

Questa è una soluzione di base. Potresti volerlo modificare, ma penso che dovresti cogliere l'idea.

+0

Questo è quello che ho con "avere un elenco interno di gestori, un" add "- e" remove "-handler function, e licenziare ogni gestore quando voglio licenziare l'evento" =) Grazie! –

+0

@DominikKirschenhofer Cool. Ho dimenticato il comando 'remove', quindi l'ho appena aggiunto. Dovrebbe funzionare. :) – freakish

+1

Per quanto riguarda la parte "difficile" - rimuovere i gestori passando lo stesso oggetto funzione: lo stesso vale per i gestori di eventi nativi. Ho appena testato un evento click' di un pulsante, e 'removeEventListener' non ha funzionato a meno che non avessi fornito un riferimento allo stesso oggetto funzione. – GolfWolf

1

Non sono sicuro su tutti al 100% ma la prossima è il risultato del mio vecchio ricerche all'interno di questo problema:

  • Non si può mettere a disposizione in qualche modo questo.
  • È possibile implementare semplicemente la propria logica. Per questo è possibile utilizzare il codice presente nell'articolo MDN element.removeEventListener con piccole modifiche. Sotto di esso copiare \ passato di codice da collegamento 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); } 
    } 
    }; 
} 
  • Penso che ciò che tutto ciò che serve per cambiare è quello di sostituire Element.prototype con CustomObject.prototype. E per supportare dispathEvent devi aggiungere la riga di codice CustomObject.prototype.dispatchEvent = runListener;. Inoltre può essere meglio racchiudere questo codice nella funzione di chiusura;

Non ho provato questo nelle mie app ma forse questo può aiutarti.

UPDATE: punti successivi link nel codice sorgente che contiene XObject() classe che supporta evento aggiunta/rimozione e dispacciamento eventi. L'esempio di prova è incluso. Tutto il codice è basato sulla risposta sopra. http://jsfiddle.net/8jZrR/

+0

@Dominik Kirschenhofer, vedere link in ** AGGIORNAMENTO: ** paragrafo –

+0

COOL! Grazie! –

1

Ho migliorato il mio esempio con il codice da freakish. Estraggerei ancora la parte eventhandling in una "classe base" ... forse quando c'è più tempo =)

C'è anche un esempio per usare 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> 

Problemi correlati