Utilizzando YUI 3 a Costruire il Torneo Yahoo! Sports Gioco Pick'em

19 Marzo, 2010 alle 06:46 da Mark Kawakami | In Sviluppo | Commenti disabilitati

Segna Kawakami Circa l'autore: Mark Kawakami ( @ skippykawakami su Twitter ) è un ingegnere frontend sulle Yahoo! Sport team di Yahoo!

Ogni marzo, gli utenti in tutto il mondo affollano Yahoo! Fantasy Sports a fare la nostra staffa Torneo NCAA gioco ", Torneo Pick'Em . "E 'uno dei nostri giochi più popolari.

In molti modi, è anche uno dei nostri più semplici. Basta compilare il vostro supporto, selezionando le squadre che ci si aspetta vincerà. Sembra facile, vero? Beh c'è un problema - ci sono 9.223.372.036.854.780.000 diversi modi possibili si può riempire il vostro supporto fuori.

Quel numero assurdamente enorme rappresenta una sfida anche per noi. Come si fa a fare qualcosa con 9 quintilioni di combinazioni possibili così facile da usare che l'utente può compilare la loro parentesi in appena un paio di minuti? La risposta implica una buona dose di JavaScript sotto il cofano, che noi chiamiamo il nostro "motore staffa".

Il supporto motore che ha utilizzato dal 2004 ci aveva servito bene, ma dopo sei tornei NCAA che stava cominciando a mostrare gli anni. La Biblioteca YUI non esisteva nemmeno quando è stato scritto (se è per questo, neppure JSON o Firebug). Così per gioco di quest'anno, abbiamo deciso che invece di miglioramenti incrementali che normalmente fanno, avremmo ripartire da zero. Ricostruire da zero ci ha dato l'opportunità di modernizzare completamente il nostro supporto motore, quindi è giusto che siamo andati così moderno come potremmo usando YUI 3. Questo sarebbe uno dei primi progetti Yahoo! Fantasy Sports ha costruito con YUI 3, ma, a questo punto, sapevamo che i punti di forza della biblioteca erano troppo grande per lasciarsela sfuggire. Fortunatamente, il supporto motore nuovo si è rivelato ancora meglio di quanto avessimo sperato.

Yahoo! Fantasy Sports Tourney Pick'em

YUI 3 si è rivelata ideale per la costruzione delle complesse interazioni che volevamo per il supporto motore. Siamo passati da un'interfaccia interamente basato sui click in un drag and drop, e YUI 3 drag-and-drop sono così facili da usare che era praticamente la prima cosa che abbiamo ottenuto lavorando. Siamo passati da un'interfaccia costruita interamente da JavaScript per quello in cui viene redatta la staffa con HTML e CSS e poi migliorato con JavaScript. Questo significava alcune immersioni abbastanza profonde nel DOM, ma l'uso YUI 3 di selettori CSS quasi ovunque in poco tempo di questi.

Entrando in questo progetto, ho capito che il drag-and-drop e CSS capacità selettore di YUI 3 si sarebbe rivelato prezioso, ma ho continuato a essere sorpreso di come molti altri utili elementi di YUI 3 sarebbe. Per questo post, mi piacerebbe esplorare uno che non riceve altrettanta attenzione: Y.Base . ( di base è parte dell'infrastruttura componente YUI, YUI e ingegnere Satyen Desai ha una bella introduzione a quella serie di strumenti su YUI Theater .)

Y. base è Pumpin '

Mentre si lavora sul supporto motore, ho scoperto che Y.Base è stato incredibilmente utile. Ci sono due cose importanti che si riceve con Y.Base : attributi ed evento di targeting. Entrambi sono stati molto più utili di quanto mi aspettassi. YUI 3 non richiede l'utilizzo di Y.Base quando si creano le proprie classi, ma per qualsiasi classe creo che sia anche un po 'non banali, ho intenzione di usare Y.Base come punto di partenza.

Attributi

Attributi vi darà la possibilità di configurare facilmente un oggetto quando lo si crea un'istanza. Se avete usato molti widget YUI o utilità, questo sarà familiare:

 var config = {
     'Nodo': nodo,
     'Durata': 0,25,
     'Allentamento': Y.Easing.easeOut
 };
 var = new anim Y. Anim (config);

Nell'esempio sopra la config variabile è un esempio di attributi in azione. Ma si ottiene di più che semplificare il processo di istanziare oggetti complessi. È possibile definire getter, setter, i valori di default, ecc Ma per me, il vero potere si presenta come valori degli attributi sono cambiati. Immediatamente prima e immediatamente dopo aver modificato il valore di un attributo, un evento viene generato, permettendo al vostro codice di rispondere ai cambiamenti al tuo oggetto.

Per esempio, nel nostro motore di supporto, quando un utente fa clic su una piccola icona per un matchup, una si apre popup che visualizza le informazioni su come le due squadre pila una contro l'altra.

Il popup è rappresentato in JavaScript da una classe che noi chiamiamo MatchupPanel . MatchupPanel ha un attributo denominato matchup che memorizza un riferimento all'oggetto matchup visualizzato. Un listener di eventi all'interno MatchupPanel entra in azione ogni volta che la matchup cambiamenti attributi. Quindi, per cambiare ciò che matchup che stiamo visualizzando nel popup, abbiamo semplicemente cambiare il matchup attributo.

 MatchupPanel var = function () {
     MatchupPanel.superclass.constructor.apply (questo, argomenti);
 }

 MatchupPanel.NAME = "matchuppanel";
 MatchupPanel.ATTRS = {
     "TeamA": {valore: null},
     "TeamB": {valore: null},
     "Contenitore": {valore: null},
     "Matchup": {valore: null},
     ...
 };

 Y.extend (MatchupPanel, Y. Base, {
     inizializzatore: function () {
         ...
         this.after ("matchupChange", this.afterMatchupChange);
     },
     ...
     afterMatchupChange: function (e) {
         var m = this.get ("match");
         if (m) {
             var = game1 m.get ("game_1");
             var = Game2 m.get ("game_2");
             team_1 var = game1.getValue ();
             team_2 var = game2.getValue ();
             if (team_1 & & team_2) {
                 this.setupDisplay (team_1, team_2);
                 this.show ();
             }
             else {
                 this.hide ();
             }
         }
         else {
             this.hide ();
         }
     },
     ...
 }
  

Eventi

Y.Base incorpora anche YUI 3 di eventi personalizzati e bubbling degli eventi personalizzati . Ciò significa che non solo è facile creare e generare eventi personalizzati, è facile per gli altri oggetti di rispondere ad essi, compresa la sospensione di propagazione come l'evento bolle la catena degli obiettivi è stata specificata, così come bolla del browser gli eventi fino al DOM gerarchia.

Per le staffe, abbiamo usato questo in pochi luoghi. Per esempio, come le squadre utente avanza attraverso i turni, le combinazioni matchup si formano nuove. Il vincitore dei primi giochi e la seconda nella prima prova di fronte all'altro nella prima partita nel secondo round, e abbiamo per visualizzare l'icona per il matchup popup.

Il Matchup oggetto è responsabile per mostrare o nascondere l'icona, mentre ogni gioco all'interno di un matchup è rappresentata da un TeamGame oggetto. Quando una squadra è avanzata in un TeamGame oggetto, l'oggetto genera un evento. Dichiarando che il Matchup oggetto è un obiettivo per il TeamGame eventi 's, il Matchup sa quando uno dei suoi cambiamenti giochi e può nascondere o mostrare l'icona come necessario.

Ecco un (molto) esempio semplificato di questa azione in per il Matchup oggetto:

 Marble var = function () {
     Matchup.superclass.constructor.apply (questo, argomenti);
 }

 Matchup.NAME = "matchup";
 Matchup.ATTRS = {
     "Contenitore": {valore: null},
     "Game_1": {valore: null},
     "Game_2": {valore: null},
     "Id": {valore: null},
     "Infotrigger": {valore: null}
     ...
 }

 Y.extend (Marble, Y. Base, {
     inizializzatore: funzionali (CFG) {
         var = li this.get ("contenitore");
         var = giochi li.all ("li.ysf-TPE-gioco");
         ...
         / / Crea gli oggetti TeamGame per questo matchup
         for (var x = 0; x <games.size (); x + +) {
             var gameNode games.item = (x);

             gameobj var = new TeamGame ({
                 "Matchup": questo,
                 "Contenitore": gameNode
             });
             if (this.get ("game_1") == null) {
                 this.set ("game_1", gameobj);
             }
             else if (this.get ("game_2") == null) {
                 this.set ("game_2", gameobj);
             }

             / / Permettono TeamGame gli eventi bolla a questo matchup
             gameobj.initTarget (this);

         }
         ...
     },
     initHandlers: function () {
         this.on ("teamgame: cambiato", this.onMatchupChange);
         this.onMatchupChange ();
     },
     onMatchupChange: function (e) {
         / / Ogni volta che uno dei cambiamenti giochi di questo match è
         / / Questo controllo per vedere se l'icona di informazioni deve
         / / Essere nascosta o visualizzata.
         ...
    },
    ...
 }

... E per la TeamGame oggetto:

 TeamGame var = function () {
     TeamGame.superclass.constructor.apply (questo, argomenti);
     this.publish ("cambiato", {prefisso: "teamgame"});
 }

 TeamGame.NANE = "teamgame";
 TeamGame.ATTRS = {
     "Contenitore": {valore: null},
     "Matchup": {valore: null},
     "Selezionare": {valore: null},
     "Gameid": {valore: null}
     ...
 }

 Y.extend (TeamGame, Y. Base, {
     inizializzatore: funzionali (CFG) {
         var cont = this.get ("contenitore");
         if (cont) {
             var sel = cont.one ("select");
             this.set ("select", sel);
             var cont.getAttribute sid = ("id");
             var = gameid TeamGame.getGameId (sid);
             this.set ("gameid", gameid);
         }
     },
     initTarget: function (match) {
         / / Lasciare un matchup per essere un bersaglio per gli eventi di questo gioco.
         var targ = matchup | | this.get ("match");
         this.addTarget (Targ);
     },
     setValue: function (val) {
         / / Imposta il menu di selezione per un dato valore.
         / / Questo è ciò che accade dietro le quinte quando
         / / Un utente effettua il loro picconi.
         var = oldValue this.getValue ();
         var sel = Y.Node.getDOMNode (this.get ("select"));
         opta var = sel.options;
         var selIdx = null;
         for (var x = 0; x opts.length <; x + +) {
             if (opta [x]. valore == val) {
                 selIdx = x;
             }
         }
         if (selIdx! == null) {
             sel.selectedIndex = selIdx;
             var = newValue this.getValue ();
             var = gameid this.get ("gameid");
             this.fire ("teamgame: cambiato", {
                 "Gioco": gameid,
                 "Vecchio": oldValue,
                 "Nuovo": newValue
             });
             ritorno selIdx;
         }
         return false;
     },
     getValue: function () {
         var select = this.get ("select");
         ritorno parseInt (select.get ("valore"));
     },
     ...
 }

Grazie alla combinazione di eventi e attributi in una classe facilmente esteso, Y.Base si occupa di un sacco di tubature una web app complesso richiede. Per me, il più grande vantaggio è che posso delineare un rapido box-and-frecce schema di come vorrei la mia applicazione al lavoro, e rapidamente trasformarla in JavaScript di lavoro.

Se volete vedere tutto questo (e altro) in azione, c'è ancora tempo per iscriversi per il nostro altro gioco del torneo NCAA, " Second Chance Pick'Em Tourney ". E questo è un po 'più facile, c'è solo 32.768 modi per riempire la staffa.

Condividere ed estendere: Bookmark with del.icio.us | Digg it! | reddit!

Nessun commento ancora

Al momento l'inserimento di commenti non è in questo momento.

Ospitato da Yahoo!

Copyright © 2006-2012 Yahoo! Inc. Tutti i diritti riservati. Privacy Policy - Termini del Servizio

Powered by WordPress su Yahoo! Web Hosting .