2013-01-19 12 views
8

Sto cercando di capire le classi jQuery ma non sta andando molto bene.Creazione di una semplice classe JavaScript con jQuery

Il mio obiettivo è quello di utilizzare una classe in questo modo (o per imparare un modo migliore per farlo):

var player = new Player($("playerElement")); 
player.InitEvents(); 

Utilizzando esempi di altre persone, questo è quello che ho provato:

$.Player = function ($) { 

}; 

$.Player.prototype.InitEvents = function() { 

    $(this).keypress(function (e) { 
     var key = e.which; 
     if (key == 100) { 
      MoveRight(); 
     } 
     if (key == 97) { 
      MoveLeft(); 
     } 
    }); 
}; 

$.Player.prototype.MoveRight = function() { 
    $(this).css("right", this.playerX += 10); 
} 

$.Player.prototype.MoveLeft = function() { 
    $(this).css("right", this.playerX -= 10); 
} 

$.Player.defaultOptions = { 
    playerX: 0, 
    playerY: 0 
}; 

L'obiettivo finale è quello di far muovere un personaggio sullo schermo a sinistra ea destra usando le lettere della tastiera A e D.

Ho la sensazione che sto facendo qualcosa di molto sbagliato con questa "classe" ma non sono sicuro del perché.

(mi dispiace per il mio inglese)

+0

'this' all'interno dei metodi di istanza fa riferimento l'oggetto istanza così da non poter usare '$ (this) .keypress',' $ (this) .css' ecc perché 'this' non fa riferimento a un elemento DOM né a una stringa di query. Anche le chiamate alle funzioni sono sbagliate, dovrebbe leggere "questo".MoveRight() 'ma siccome sei all'interno di un gestore jQuery che imposta il contesto' this' sull'elemento DOM stesso, dovrai assegnare l'istanza 'this' a una variabile di livello superiore nella catena dell'ambito in modo che tu possa accedervi all'interno del gestore per chiamare i suoi metodi 'MoveRight' /' MoveLeft'. –

+0

puoi mostrarmi come cambierai il mio codice per risolvere il problema che ho fatto? sarà molto più facile per me vedere che cosa ho fatto se potessi compre un buon codice contro il mio. (se non è troppo difficile) – samy

+0

Posso provare l'uomo, ma è più vicino a una riscrittura completa che a una "correzione". ': P' Vedrò se posso fare un semplice esempio. –

risposta

19

Una questione importante è che si deve assegnare l'oggetto/elemento jQuery passato a una this.element - o di un altro this.propertyName - in modo da può accedervi più tardi all'interno dei metodi dell'istanza.

Non è inoltre possibile chiamare MoveRight()/MoveLeft() direttamente così perché quelle funzioni non sono definite nella catena campo di applicazione, ma piuttosto nel prototipo del del l'istanza di costruzione, quindi avete bisogno di un riferimento all'istanza stessa a chiamare questi.

aggiornato e commentato codice qui sotto:

(function ($) { //an IIFE so safely alias jQuery to $ 
    $.Player = function (element) { //renamed arg for readability 

     //stores the passed element as a property of the created instance. 
     //This way we can access it later 
     this.element = (element instanceof $) ? element : $(element); 
     //instanceof is an extremely simple method to handle passed jQuery objects, 
     //DOM elements and selector strings. 
     //This one doesn't check if the passed element is valid 
     //nor if a passed selector string matches any elements. 
    }; 

    //assigning an object literal to the prototype is a shorter syntax 
    //than assigning one property at a time 
    $.Player.prototype = { 
     InitEvents: function() { 
      //`this` references the instance object inside of an instace's method, 
      //however `this` is set to reference a DOM element inside jQuery event 
      //handler functions' scope. So we take advantage of JS's lexical scope 
      //and assign the `this` reference to another variable that we can access 
      //inside the jQuery handlers 
      var that = this; 
      //I'm using `document` instead of `this` so it will catch arrow keys 
      //on the whole document and not just when the element is focused. 
      //Also, Firefox doesn't fire the keypress event for non-printable 
      //characters so we use a keydown handler 
      $(document).keydown(function (e) { 
       var key = e.which; 
       if (key == 39) { 
        that.moveRight(); 
       } else if (key == 37) { 
        that.moveLeft(); 
       } 
      }); 

      this.element.css({ 
       //either absolute or relative position is necessary 
       //for the `left` property to have effect 
       position: 'absolute', 
       left: $.Player.defaultOptions.playerX 
      }); 
     }, 
     //renamed your method to start with lowercase, convention is to use 
     //Capitalized names for instanceables only 
     moveRight: function() { 
      this.element.css("left", '+=' + 10); 
     }, 
     moveLeft: function() { 
      this.element.css("left", '-=' + 10); 
     } 
    }; 


    $.Player.defaultOptions = { 
     playerX: 0, 
     playerY: 0 
    }; 

}(jQuery)); 

//so you can use it as: 
var player = new $.Player($("#playerElement")); 
player.InitEvents(); 

Fiddle

Si noti inoltre che JavaScript non sia effettivamente "classi" (almeno non fino a ES6 viene implementata), né metodi (che per definizione sono associati esclusivamente alle Classi), ma piuttosto dei Costruttori che forniscono una sintassi dolce che ricorda le classi. Ecco un articolo fantastico scritto da TJ Crowder quanto riguarda i metodi "falsi" di JS, è un po 'avanzato, ma tutti dovrebbero essere in grado di imparare qualcosa di nuovo da lettura:
http://blog.niftysnippets.org/2008/03/mythical-methods.html

2

Quando si utilizza this dentro le Player funzioni prototipo, this punti all'oggetto Player corrente.

Tuttavia, quando si utilizza $(this).keypress, è necessario che i punti this vengano convertiti in un elemento HTML.

I due semplicemente sono incompatibili. C'è solo uno this e punta all'oggetto Player corrente, non a un elemento HTML.

Per risolvere il problema, è necessario passare l'elemento HTML nell'oggetto Player al momento della sua creazione o nelle relative chiamate di funzione.

È possibile passare l'elemento nell'oggetto Player su costruzione in questo modo:

$.Player = function ($, element) { 
     this.element = element; 

}; 

$.Player.prototype.InitEvents = function() { 

    $(this.element).keypress(function (e) { 
     var key = e.which; 
     if (key == 100) { 
      MoveRight(); 
     } 
     if (key == 97) { 
      MoveLeft(); 
     } 
    }); 
}; 

$.Player.prototype.MoveRight = function() { 
    $(this.element).css("right", this.playerX += 10); 
} 

$.Player.prototype.MoveLeft = function() { 
    $(this.element).css("right", this.playerX -= 10); 
} 

$.Player.defaultOptions = { 
    playerX: 0, 
    playerY: 0 
}; 
+0

scusa per la mia ignoranza ma come faccio a usare questa lezione? Voglio dire se lo uso il motivo per cui mostro nel mio lavoro non funziona. (se non è così difficile) puoi aggiungere un esempio? (grazie per aver trovato il tempo di rispondere alla mia domanda) – samy

Problemi correlati