Utilizzo del prototipo di JavaScript con MVC

In questo articolo, esamineremo il processo di utilizzo di JavaScript, da una prospettiva basata su MVC, per manipolare il DOM. Più specificamente, progetteremo i nostri oggetti JavaScript, le loro proprietà e metodi e le loro istanze parallelamente al comportamento previsto delle nostre visualizzazioni (ciò che l'utente vede).


Considera le tue viste come oggetti, non come pagine

In qualsiasi momento dello sviluppo di una pagina Web, stiamo utilizzando un linguaggio che promuove naturalmente lo sviluppo basato su classi o lo sviluppo basato su oggetti. In linguaggi fortemente tipizzati come Java e C #, di solito scriviamo le nostre viste in classi, dando loro stato, ambito e contesto. Quando lavoriamo con linguaggi come PHP o motori di visualizzazione più recenti, come Razor per ASP.NET, le nostre viste possono semplicemente essere marcate (HTML / CSS) mescolate con il template. Tuttavia, questo non significa che dobbiamo cambiare la nostra percezione di come la vista si comporta come una propria entità statica.

All'interno di Views, stiamo principalmente lavorando con HTML, che consiste di elementi nidificati; questi elementi hanno attributi che descrivono quale sia il loro scopo semantico o come appaiono quando sono resi. Questi elementi hanno quindi elementi figli o genitori che ereditano / forniscono comportamenti a cascata (tramite CSS) e di blocco / in linea. Questi elementi possono essere naturalmente visualizzati da una prospettiva OOP (Object-Oriented Programming). Si consideri, ad esempio, il seguente markup:

 div.container border: 1px solid # 333; imbottitura: 5px; colore rosso; 
 

Riguardo la nostra compagnia

Risultato:

Come puoi vedere sopra, l'intestazione ha ereditato la sua proprietà color font dal suo contenitore genitore attraverso il comportamento CSS della cascata. Questo comportamento è abbastanza simile al concetto di ereditarietà in OOP. Possiamo anche vedere che l'intestazione è un figlio del contenitore, ereditando determinate proprietà, in base al comportamento dell'elemento. Quando vediamo i nostri elementi da questa prospettiva, abbiamo una definizione migliore di ciò che intendiamo fare con i nostri elementi di visualizzazione e possiamo incapsulare meglio stili e funzionalità.

All'interno di una vista, avremo markup. Tuttavia, questo markup può avere viste parziali nidificate come barre laterali, un'intestazione, un piè di pagina, una guida a destra (o sinistra) e una o più sezioni di contenuto. Tutte queste viste parziali dovrebbero essere viste come una propria entità, in grado di avere il proprio stato, contesto e ambito.

"Quando si concepiscono le viste e le viste parziali come oggetti, è molto più semplice scrivere il codice lato client."


Traduzione di questo concetto nei tuoi stili e script

Molti sviluppatori tendono a scrivere JavaScript da un punto di vista procedurale o funzionale, e spesso trascurano di considerare le tendenze naturali offerte negli approcci di sviluppo basati sulla vista e nell'istanza parallela (creando una nuova istanza della vista quando creiamo una nuova istanza di un JavaScript oggetto corrispondente a quella vista) quando si lavora in MVC Frameworks. Capita spesso di incappare in file JavaScript che sono solo un metodo dopo l'altro. Sebbene questo comportamento funzioni e sia comune, non è molto efficiente per la manutenzione del codice, il debug o l'estensione del codice corrente o futuro quando si lavora ampiamente con le viste.

Per allontanarti da questa abitudine e iniziare a scrivere un codice comportamentale migliore, quando inizi a disporre gli script e gli stili della tua vista, segui queste regole generali:

Regole d'oro per lo sviluppo di JavaScript basato su View

  • Ogni vista resa da un'azione su un controller dovrebbe avere il proprio oggetto JavaScript.
  • Ogni vista parziale caricata all'interno di una vista dovrebbe avere il proprio oggetto JavaScript.
  • Assegna un nome ai tuoi oggetti allo stesso modo delle tue viste (o viste parziali). Questo avrà più senso per te e tutti gli altri che toccano il tuo codice.
  • Utilizzare la custodia Pascal per tutti gli oggetti (ad esempio Informazioni, Barra laterale, ecc.). Le tue visualizzazioni dovrebbero già, quindi perché non fare lo stesso per i tuoi oggetti JavaScript?
  • Tutte le costanti di questi oggetti devono essere memorizzate nel costruttore. Ciò significa che se la tua vista ha proprietà che verranno utilizzate in più metodi, questi metodi possono tutti accedere a queste proprietà.
  • Tutti i metodi che verranno chiamati su una vista (o vista parziale) dovrebbero essere associati al prototipo dell'oggetto che corrisponde a quella vista.
  • Tutti i binding di eventi per la vista (o la vista parziale) devono essere contenuti all'interno del proprio metodo di associazione degli eventi, che viene posizionato sul prototipo.

Si consideri il seguente diagramma:

Generalmente creo script e stili specifici per le viste e poi afferro ciò che mi serve dai fogli di stile e dalle librerie di script principali che ho creato che sarebbero stati usati su molte viste. Questo riduce anche la quantità di codice che viene utilizzato.


Creazione di oggetti basati su viste

In questo articolo, definiremo la struttura per la pagina Chi siamo su un sito basato su MVC. Per iniziare, creeremo la struttura come mostrato sopra nel diagramma precedente. Da lì, creeremo un oggetto About e inizieremo ad aggiungere metodi al prototipo. Innanzitutto, considera il seguente layout visivo:

Questo è un layout molto logico e comunemente usato per una pagina web. Possiamo segmentare la nostra pagina in oggetti visivi separati. Per ognuna di queste viste, possiamo creare un oggetto logico che corrisponderà ad esso. In genere ometto le informazioni ripetitive nel nome file o nel nome della classe che viene utilizzato da MVC per determinare l'URI dalla rotta e invece si attaccano a qualcosa che è facile da mantenere coerente.

Per le visualizzazioni di pagina, generalmente chiamo i miei oggetti JavaScript con il nome della vista. Ecco un esempio del mio oggetto AboutView:

 // Visualizza nome file: AboutView.cs (.NET MVC 1.0), About.cshtml (.NET MVC 3.0) o AboutView.php (PHP) var About = function (pageTitle) this.pageTitle = pageTitle; // associa gli eventi non appena l'oggetto viene istanziato this.bindEvents (); ;

Nell'esempio precedente, abbiamo creato un oggetto JavaScript nel formato della funzione, dandogli la capacità di fungere da costruttore di oggetti per tutti i metodi chiamati per la vista about. Scegliendo questo formato, possiamo creare un'istanza di una nuova istanza di Questo, proprio come facciamo con la nostra vista lato server (dicendo nuovo AboutView ();). Da qui, possiamo assegnare proprietà e metodi a questo oggetto. Per assegnare metodi a questo oggetto, avremo bisogno di accedere al prototipo dell'oggetto.


Il prototipo di JavaScript è tuo amico

Gli sviluppatori sono spesso ostacolati dall'elusività (e dall'ambiguità) del prototipo Object di JavaScript.

Gli sviluppatori sono spesso ostacolati dall'elusività (e dall'ambiguità) del prototipo Object di JavaScript. Per molti, può essere fonte di confusione usare e comprendere e aggiunge un'altra dimensione alla codifica. Poiché JavaScript diventa più guidato dagli eventi con i concetti HTML5, AJAX e Web 2.0, JavaScript tende a propendere naturalmente allo sviluppo procedurale facile da sviluppare ma difficile da mantenere, scalare e replicare.

Pensa alla parola Prototipo come un termine improprio per ora. Quando penso Prototipo, Penso a una "bozza di massima" o una base per l'ereditarietà, ma non è esattamente il caso.

"In realtà, la prospettiva migliore per Prototype sarebbe il puntatore dell'oggetto in memoria."

Quando creiamo un oggetto, istanziamo una nuova istanza di esso. Quando lo facciamo, creiamo un posto in memoria che l'oggetto possa essere referenziato (ricorda, gli oggetti in JavaScript lo sono tipi di riferimento, tipi non primitivi; creando un'altra variabile uguale a quell'oggetto e quindi cambiando i suoi valori in realtà cambierà l'oggetto originale nel puntatore). Quando creiamo un oggetto, istanziamo una nuova istanza di esso, quindi modifichiamo il suo "Puntatore" o Prototipo, aggiungiamo campi e metodi a quell'oggetto direttamente in memoria (ovviamente vogliamo aggiungere tutte queste cose prima dell'istanziazione).

Ecco un esempio di creazione di metodi su Di prototipo dell'oggetto:

 var About = function (pageTitle) this.pageTitle = pageTitle; // associa gli eventi non appena l'oggetto viene istanziato this.bindEvents (); ; var About.prototype.bindEvents = function () // Contesto corrente: 'this' è l'oggetto About // Posiziona tutte le associazioni di eventi in un unico posto e richiamale // nei propri metodi, se necessario. $ ('ul.menu'). on ('click', 'li.search', $ .proxy (this.toggleSearch, this)); ; var About.prototype.toggleSearch = function (e) // Attiva / disattiva la funzione di ricerca nella pagina;

Come puoi vedere sopra, abbiamo contenuto le proprietà dell'oggetto About all'interno del costruttore, abbiamo creato un singolo punto di riferimento per gli eventi di binding (in questo caso stiamo usando jQuery per creare i binding di evento, ma puoi usare qualsiasi framework o JavaScript stesso) e hanno posizionato il metodo toggleSearch sul prototipo dell'oggetto About per contenere quel metodo su quell'oggetto. Abbiamo anche chiamato il bindEvents () metodo nell'oggetto in modo che venga chiamato in istanza.

Ora, considera il seguente codice per la vista parziale della sidebar:

 var pSidebar = function (pageTitle) this.pageTitle = pageTitle; // chiama il metodo bindEvents sulla creazione di istanze dell'oggetto pSidebar. // questo collegherà gli eventi all'oggetto this.bindEvents (); ; var pSidebar.prototype.bindEvents = function () // contesto corrente: 'this' è l'oggetto Sidebar $ ('ul.menu'). on ('click', 'li.has-submenu', $ .proxy ( this.toggleSubMenu, this)); $ ('input # search'). on ('click', $ .proxy (this.openSearch, this)); ; var pSidebar.prototype.toggleSubMenu = function (e) // attiva / disattiva i sottomenu // contesto corrente: 'this' is the pSidebar obj;

NOTA: Ho chiamato l'oggetto pSidebar perché questo è un vista parziale, non una visione completa. Questa è la mia preferenza per distinguere tra i due, ma rende le cose più chiare.

La bellezza di usare questo approccio è - possiamo usare gli stessi nomi di metodo che abbiamo usato nell'oggetto About e non avremo conflitti. Questo perché questi metodi sono legati a quelli dell'oggetto prototipo stesso, non lo spazio dei nomi globale. Questo semplifica il nostro codice e consente una sorta di "modello" per lo scripting futuro.


Istanziare solo se necessario

Una volta creati gli oggetti, chiamarli è semplice. Non è più necessario dipendere dal framework per attivare eventi quando il documento è caricato o pronto. Ora puoi semplicemente istanziare il tuo oggetto e i suoi eventi saranno vincolati ed eseguiti secondo necessità. Quindi, istanziamo il nostro Di oggetto:

All'interno della tua vista, dove chiameresti script specifici della tua vista (dipende dalla tua lingua dei template), chiama semplicemente una nuova istanza del tuo oggetto e includi il file come segue:

  

Come puoi vedere, ho passato il titolo della pagina per la vista (che può essere qualsiasi argomento per qualsiasi necessità - anche Dati modello. Questo ti offre un contesto eccellente sui dati del tuo modello e ti consente di manipolare i dati in JavaScript molto facilmente.

Proprio come il tuo Di Oggetto, chiamare le tue viste parziali è altrettanto facile. Consiglio vivamente di chiamare nuove istanze degli oggetti JavaScript con vista parziale all'interno del costruttore dell'oggetto: ciò garantisce che le chiamate solo quando necessario e che siano collettivamente in un unico punto.

 var About = function (pageTitle) this.pageTitle = pageTitle; // assegnando una nuova istanza della Vista parziale della sidebar da riferire successivamente this.sidebar = new pSidebar (pageTitle); // NOTA: se non hai bisogno di fare riferimento a una vista parziale dopo il fatto, // puoi semplicemente istanziare un'istanza di essa senza assegnarla all'interno del costruttore dell'oggetto, in questo modo: new pSidebar (pageTitle); // facendo lo stesso per il Piè di pagina parziale Visualizza this.footer = new pFooter (); // associa gli eventi non appena l'oggetto viene istanziato this.bindEvents (); ;

Come puoi vedere, facendo riferimento all'oggetto Sidebar come proprietà locale dell'oggetto About, ora associamo quell'istanza, che è un comportamento molto naturale - questa istanza è ora la sidebar della pagina About..

Se non hai bisogno di fare riferimento a una vista parziale dopo il fatto, puoi semplicemente istanziare un'istanza di essa senza assegnarla all'interno del costruttore dell'oggetto, in questo modo:

 var About = function (pageTitle) this.pageTitle = pageTitle; nuova pSidebar (pageTitle); // associa gli eventi non appena l'oggetto viene istanziato this.bindEvents (); ;

Da qui, tutto ciò che dobbiamo fare è aggiungere un altro script ai nostri script chiamati nella nostra vista:

   

Perché questa tecnica è benefica

Una volta che questa struttura è a posto, possiamo quindi personalizzare il nostro oggetto JavaScript per abbinare la nostra vista e applicare i metodi necessari a quell'oggetto per mantenere l'ambito. Creando un oggetto parallelo alla vista e lavorando sul prototipo dell'oggetto, vediamo i seguenti vantaggi:

  1. La nomenclatura facilita la navigazione nel codice
  2. Ovviamente abbiamo un namespace per i nostri oggetti, riducendo la necessità di nomi di metodi lunghi e un uso eccessivo della chiusura anonima.
  3. Nessun conflitto in nessun altro codice perché i nostri metodi sono sul prototipo dell'oggetto, non a livello globale
  4. Quando istanziamo le nostre viste parziali all'interno del costruttore di oggetti View e assegnandole a un riferimento di variabile locale, creiamo in modo efficace una copia rilegata localmente dell'oggetto di quella vista parziale.
  5. Abbiamo una definizione precisa del contesto e siamo in grado di utilizzare la parola chiave "questo" senza preoccupazioni.
  6. Il debug diventa chiaro perché tutti i metodi mostrati nello stack sono rilegati in un unico posto.

Conclusione

Dato che MVC Design Pattern continua a diventare più popolare nel mondo del design, lo sviluppo di oggetti JavaScript per accompagnare la manipolazione del DOM Element cambierà in modo più mirato alla manipolazione specifica della vista e all'evento. Personalizzando i nostri oggetti JavaScript per creare un'istanza in parallelo con le nostre viste, possiamo avere una relazione di stato mano-in-mano tra i due, che è similmente di buon gusto, facile da gestire, semplice da mantenere e perfetto per l'espansione come la vista cresce o cambia, creando una relazione permeabile ed espandibile tra markup e scripting.

Utilizzando un prototipo di oggetto, siamo in grado di mantenere un preciso contesto sull'oggetto di scripting della nostra vista ed espandere quell'oggetto con uno stato mentale di sviluppo ripetitivo. Possiamo quindi replicare questo formato attraverso le nostre viste parziali, risparmiandoci tempo, potenza del cervello e rischio di bug e comportamenti imprevisti.